diff --git a/components/fpspreadsheet/examples/excel2demo/excel2write.lpr b/components/fpspreadsheet/examples/excel2demo/excel2write.lpr
index 27dba658f..46a740151 100644
--- a/components/fpspreadsheet/examples/excel2demo/excel2write.lpr
+++ b/components/fpspreadsheet/examples/excel2demo/excel2write.lpr
@@ -20,6 +20,8 @@ var
number: Double;
lCol: TCol;
lRow: TRow;
+ r: Integer;
+ fmt: String;
begin
// Open the output file
MyDir := ExtractFilePath(ParamStr(0));
@@ -34,7 +36,7 @@ begin
MyWorksheet.WriteRowHeight(0, 30); // 30 mm
// Turn off grid lines and hide headers
- MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines, soShowHeaders];
+ //MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines, soShowHeaders];
{ -- currently not working
//MyWorksheet.Options := MyWorksheet.Options + [soHasFrozenPanes];
@@ -108,67 +110,240 @@ begin
MyWorksheet.WriteNumber(6, 3, 2017);
MyWorksheet.WriteFont(6, 3, 'Arial', 18, [fssBold], scBlue);
- // Write current date/time to cells B11:B16
- MyWorksheet.WriteUTF8Text(10, 0, 'nfShortDate');
- MyWorksheet.WriteDateTime(10, 1, now, nfShortDate);
- MyWorksheet.WriteUTF8Text(11, 0, 'nfShortTime');
- MyWorksheet.WriteDateTime(11, 1, now, nfShortTime);
- MyWorksheet.WriteUTF8Text(12, 0, 'nfLongTime');
- MyWorksheet.WriteDateTime(12, 1, now, nfLongTime);
- MyWorksheet.WriteUTF8Text(13, 0, 'nfShortDateTime');
- MyWorksheet.WriteDateTime(13, 1, now, nfShortDateTime);
- MyWorksheet.WriteUTF8Text(14, 0, 'nfFmtDateTime, DM');
- MyWorksheet.WriteDateTime(14, 1, now, nfFmtDateTime, 'DM');
- MyWorksheet.WriteUTF8Text(15, 0, 'nfFmtDateTime, MY');
- MyWorksheet.WriteDateTime(15, 1, now, nfFmtDateTime, 'MY');
- MyWorksheet.WriteUTF8Text(16, 0, 'nfShortTimeAM');
- MyWorksheet.WriteDateTime(16, 1, now, nfShortTimeAM);
- MyWorksheet.WriteUTF8Text(17, 0, 'nfLongTimeAM');
- MyWorksheet.WriteDateTime(17, 1, now, nfLongTimeAM);
- MyWorksheet.WriteUTF8Text(18, 0, 'nfFmtDateTime, MS');
- MyWorksheet.WriteDateTime(18, 1, now, nfFmtDateTime, 'MS');
- MyWorksheet.WriteUTF8Text(19, 0, 'nfFmtDateTime, MSZ');
- MyWorksheet.WriteDateTime(19, 1, now, nfFmtDateTime, 'MSZ');
+ r:= 10;
+ // Write current date/time and test numbers for various formatting options
+
+ MyWorksheet.WriteUTF8Text(r, 1, 'Formats in gray cells are not supported by BIFF2');
+
+ inc(r, 2);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDateTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDateTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, DM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'DM');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MY');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MY');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MS');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MS');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MSZ');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MSZ');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
// Write formatted numbers
number := 12345.67890123456789;
- MyWorksheet.WriteUTF8Text(24, 1, '12345.67890123456789');
- MyWorksheet.WriteUTF8Text(24, 2, '-12345.67890123456789');
- MyWorksheet.WriteUTF8Text(25, 0, 'nfFixed, 0 decs');
- MyWorksheet.WriteNumber(25, 1, number, nfFixed, 0);
- MyWorksheet.WriteNumber(25, 2, -number, nfFixed, 0);
- MyWorksheet.WriteUTF8Text(26, 0, 'nfFixed, 2 decs');
- MyWorksheet.WriteNumber(26, 1, number, nfFixed, 2);
- MyWorksheet.WriteNumber(26, 2, -number, nfFixed, 2);
- MyWorksheet.WriteUTF8Text(27, 0, 'nfFixedTh, 0 decs');
- MyWorksheet.WriteNumber(27, 1, number, nfFixedTh, 0);
- MyWorksheet.WriteNumber(27, 2, -number, nfFixedTh, 0);
- MyWorksheet.WriteUTF8Text(28, 0, 'nfFixedTh, 2 decs');
- MyWorksheet.WriteNumber(28, 1, number, nfFixedTh, 2);
- MyWorksheet.WriteNumber(28, 2, -number, nfFixedTh, 2);
- MyWorksheet.WriteUTF8Text(29, 0, 'nfSci, 1 dec');
- MyWorksheet.WriteNumber(29, 1, number, nfSci);
- MyWorksheet.WriteNumber(29, 2, -number, nfSci);
- MyWorksheet.WriteNumber(29, 3, 1.0/number, nfSci);
- MyWorksheet.WriteNumber(29, 4, -1.0/number, nfSci);
- MyWorksheet.WriteUTF8Text(30, 0, 'nfExp, 2 decs');
- MyWorksheet.WriteNumber(30, 1, number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 2, -number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 3, 1.0/number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 4, -1.0/number, nfExp, 2);
-
+ inc(r, 2);
+ MyWorksheet.WriteUTF8Text(r, 1, '12345.67890123456789');
+ MyWorksheet.WriteUTF8Text(r, 2, '-12345.67890123456789');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfGeneral');
+ MyWorksheet.WriteNumber(r, 1, number, nfGeneral);
+ MyWorksheet.WriteNumber(r, 2, -number, nfGeneral);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 1);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 3);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 1);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 1);
+ MyWorksheet.WriteFontColor(r, 3, scGray);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 1);
+ MyWorksheet.WriteFontColor(r, 4, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 2 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 2);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 2);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 2);
+ MyWorksheet.WriteFontColor(r, 3, scGray);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 2);
+ MyWorksheet.WriteFontColor(r, 4, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 3 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 3);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
+ MyWorksheet.WriteFontColor(r, 3, scGray);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
+ MyWorksheet.WriteFontColor(r, 4, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 3, scGray);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 4, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 3, scGray);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 4, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ fmt := '"€"#,##0.0_);[Red]("€"#,##0.0)';
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, '+fmt);
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ fmt := '[Green]"¥"#,##0.0_);[Red]-"¥"#,##0.0';
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, '+fmt);
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r, 2);
number := 1.333333333;
- MyWorksheet.WriteUTF8Text(35, 0, 'nfPercentage, 0 decs');
- MyWorksheet.WriteNumber(35, 1, number, nfPercentage, 0);
- MyWorksheet.WriteUTF8Text(36, 0, 'nfPercentage, 2 decs');
- MyWorksheet.WriteNumber(36, 1, number, nfPercentage, 2);
- MyWorksheet.WriteUTF8Text(37, 0, 'nfTimeInterval');
- MyWorksheet.WriteDateTime(37, 1, number, nfTimeInterval);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm:ss');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'H:M:s');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
- // Set width of columns 0 and 1
- MyWorksheet.WriteColWidth(0, 40);
- lCol.Width := 35;
+ // Set width of columns 0 to 3
+ MyWorksheet.WriteColWidth(0, 50);
+ lCol.Width := 15;
MyWorksheet.WriteColInfo(1, lCol);
+ MyWorksheet.WriteColInfo(2, lCol);
+ MyWorksheet.WriteColInfo(3, lCol);
// Set height of rows 5 and 6
lRow.Height := 10;
diff --git a/components/fpspreadsheet/examples/excel5demo/excel5write.lpr b/components/fpspreadsheet/examples/excel5demo/excel5write.lpr
index 7c3945b13..991bdbf42 100644
--- a/components/fpspreadsheet/examples/excel5demo/excel5write.lpr
+++ b/components/fpspreadsheet/examples/excel5demo/excel5write.lpr
@@ -25,8 +25,9 @@ var
MyWorksheet: TsWorksheet;
MyRPNFormula: TsRPNFormula;
MyDir: string;
- i: Integer;
+ i, r: Integer;
number: Double;
+ fmt: string;
begin
MyDir := ExtractFilePath(ParamStr(0));
@@ -50,6 +51,8 @@ begin
MyWorksheet.WriteColWidth(0, 40);
MyWorksheet.WriteColWidth(1, 20);
MyWorksheet.WriteColWidth(2, 20);
+ MyWorksheet.WriteColWidth(3, 15);
+ MyWorksheet.WriteColWidth(4, 15);
// Write some cells
MyWorksheet.WriteNumber(0, 0, 1.0);// A1
@@ -155,62 +158,181 @@ begin
MyRPNFormula[1].ElementKind := fekABS;
MyWorksheet.WriteRPNFormula(0, 5, MyRPNFormula);
+ r:= 10;
// Write current date/time to cells B11:B16
- MyWorksheet.WriteUTF8Text(10, 0, 'nfShortDate');
- MyWorksheet.WriteDateTime(10, 1, now, nfShortDate);
- MyWorksheet.WriteUTF8Text(11, 0, 'nfShortTime');
- MyWorksheet.WriteDateTime(11, 1, now, nfShortTime);
- MyWorksheet.WriteUTF8Text(12, 0, 'nfLongTime');
- MyWorksheet.WriteDateTime(12, 1, now, nfLongTime);
- MyWorksheet.WriteUTF8Text(13, 0, 'nfShortDateTime');
- MyWorksheet.WriteDateTime(13, 1, now, nfShortDateTime);
- MyWorksheet.WriteUTF8Text(14, 0, 'nfFmtDateTime, DM');
- MyWorksheet.WriteDateTime(14, 1, now, nfFmtDateTime, 'DM');
- MyWorksheet.WriteUTF8Text(15, 0, 'nfFmtDateTime, MY');
- MyWorksheet.WriteDateTime(15, 1, now, nfFmtDateTime, 'MY');
- MyWorksheet.WriteUTF8Text(16, 0, 'nfShortTimeAM');
- MyWorksheet.WriteDateTime(16, 1, now, nfShortTimeAM);
- MyWorksheet.WriteUTF8Text(17, 0, 'nfLongTimeAM');
- MyWorksheet.WriteDateTime(17, 1, now, nfLongTimeAM);
- MyWorksheet.WriteUTF8Text(18, 0, 'nfFmtDateTime, MS');
- MyWorksheet.WriteDateTime(18, 1, now, nfFmtDateTime, 'MS');
- MyWorksheet.WriteUTF8Text(19, 0, 'nfFmtDateTime, MSZ');
- MyWorksheet.WriteDateTime(19, 1, now, nfFmtDateTime, 'MSZ');
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDateTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDateTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, DM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'DM');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MY');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MY');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MS');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MS');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MSZ');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MSZ');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
// Write formatted numbers
number := 12345.67890123456789;
- MyWorksheet.WriteUTF8Text(24, 1, '12345.67890123456789');
- MyWorksheet.WriteUTF8Text(24, 2, '-12345.67890123456789');
- MyWorksheet.WriteUTF8Text(25, 0, 'nfFixed, 0 decs');
- MyWorksheet.WriteNumber(25, 1, number, nfFixed, 0);
- MyWorksheet.WriteNumber(25, 2, -number, nfFixed, 0);
- MyWorksheet.WriteUTF8Text(26, 0, 'nfFixed, 2 decs');
- MyWorksheet.WriteNumber(26, 1, number, nfFixed, 2);
- MyWorksheet.WriteNumber(26, 2, -number, nfFixed, 2);
- MyWorksheet.WriteUTF8Text(27, 0, 'nfFixedTh, 0 decs');
- MyWorksheet.WriteNumber(27, 1, number, nfFixedTh, 0);
- MyWorksheet.WriteNumber(27, 2, -number, nfFixedTh, 0);
- MyWorksheet.WriteUTF8Text(28, 0, 'nfFixedTh, 2 decs');
- MyWorksheet.WriteNumber(28, 1, number, nfFixedTh, 2);
- MyWorksheet.WriteNumber(28, 2, -number, nfFixedTh, 2);
- MyWorksheet.WriteUTF8Text(29, 0, 'nfSci, 1 dec');
- MyWorksheet.WriteNumber(29, 1, number, nfSci);
- MyWorksheet.WriteNumber(29, 2, -number, nfSci);
- MyWorksheet.WriteNumber(29, 3, 1.0/number, nfSci);
- MyWorksheet.WriteNumber(29, 4, -1.0/number, nfSci);
- MyWorksheet.WriteUTF8Text(30, 0, 'nfExp, 2 decs');
- MyWorksheet.WriteNumber(30, 1, number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 2, -number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 3, 1.0/number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 4, -1.0/number, nfExp, 2);
-
+ inc(r, 2);
+ MyWorksheet.WriteUTF8Text(r, 1, '12345.67890123456789');
+ MyWorksheet.WriteUTF8Text(r, 2, '-12345.67890123456789');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfGeneral');
+ MyWorksheet.WriteNumber(r, 1, number, nfGeneral);
+ MyWorksheet.WriteNumber(r, 2, -number, nfGeneral);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 1);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 2 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 2);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 2);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 3 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 3);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 1);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 3);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0_);("$"#,##0)');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ inc(r);
+ fmt := '"€"#,##0.0_);[Red]("€"#,##0.0)';
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, '+fmt);
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
+ inc(r);
+ fmt := '[Green]"¥"#,##0.0_);[Red]-"¥"#,##0.0';
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, '+fmt);
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ inc(r, 2);
number := 1.333333333;
- MyWorksheet.WriteUTF8Text(35, 0, 'nfPercentage, 0 decs');
- MyWorksheet.WriteNumber(35, 1, number, nfPercentage, 0);
- MyWorksheet.WriteUTF8Text(36, 0, 'nfPercentage, 2 decs');
- MyWorksheet.WriteNumber(36, 1, number, nfPercentage, 2);
- MyWorksheet.WriteUTF8Text(37, 0, 'nfTimeInterval');
- MyWorksheet.WriteDateTime(37, 1, number, nfTimeInterval);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm:ss');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'H:M:s');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
//MyFormula.FormulaStr := '';
diff --git a/components/fpspreadsheet/examples/excel8demo/excel8read.lpi b/components/fpspreadsheet/examples/excel8demo/excel8read.lpi
index 6dea16dd6..557786999 100644
--- a/components/fpspreadsheet/examples/excel8demo/excel8read.lpi
+++ b/components/fpspreadsheet/examples/excel8demo/excel8read.lpi
@@ -34,12 +34,17 @@
-
+
+
+
+
+
+
@@ -53,6 +58,11 @@
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/excel8demo/excel8read.lpr b/components/fpspreadsheet/examples/excel8demo/excel8read.lpr
index 543528dbc..61228d310 100644
--- a/components/fpspreadsheet/examples/excel8demo/excel8read.lpr
+++ b/components/fpspreadsheet/examples/excel8demo/excel8read.lpr
@@ -11,7 +11,7 @@ program excel8read;
uses
Classes, SysUtils, fpspreadsheet, xlsbiff8,
- laz_fpspreadsheet;
+ laz_fpspreadsheet, fpsutils;
var
MyWorkbook: TsWorkbook;
@@ -21,6 +21,8 @@ var
i: Integer;
CurCell: PCell;
+{$R *.res}
+
begin
// Open the input file
MyDir := ExtractFilePath(ParamStr(0));
diff --git a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
index 6d4fcc1cd..037d1905a 100644
--- a/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
+++ b/components/fpspreadsheet/examples/excel8demo/excel8write.lpr
@@ -26,11 +26,10 @@ var
MyWorksheet: TsWorksheet;
MyRPNFormula: TsRPNFormula;
MyDir: string;
- i: Integer;
- lCell: PCell;
number: Double;
+ lCell: PCell;
lCol: TCol;
- lRow: TRow;
+ i, r: Integer;
begin
MyDir := ExtractFilePath(ParamStr(0));
@@ -41,7 +40,6 @@ begin
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet1);
MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines];
-
MyWorksheet.Options := MyWorksheet.Options + [soHasFrozenPanes];
myWorksheet.LeftPaneWidth := 1;
MyWorksheet.TopPaneHeight := 2;
@@ -129,7 +127,7 @@ begin
// Uncomment this to test large XLS files
- for i := 40 to 1000 do
+ for i := 50 to 1000 do
begin
// MyWorksheet.WriteUTF8Text(i, 0, ParamStr(0));
// MyWorksheet.WriteUTF8Text(i, 1, ParamStr(0));
@@ -158,67 +156,169 @@ begin
MyRPNFormula[1].ElementKind := fekABS;
MyWorksheet.WriteRPNFormula(0, 5, MyRPNFormula);
+ r:= 10;
// Write current date/time to cells B11:B16
- MyWorksheet.WriteUTF8Text(10, 0, 'nfShortDate');
- MyWorksheet.WriteDateTime(10, 1, now, nfShortDate);
- MyWorksheet.WriteUTF8Text(11, 0, 'nfShortTime');
- MyWorksheet.WriteDateTime(11, 1, now, nfShortTime);
- MyWorksheet.WriteUTF8Text(12, 0, 'nfLongTime');
- MyWorksheet.WriteDateTime(12, 1, now, nfLongTime);
- MyWorksheet.WriteUTF8Text(13, 0, 'nfShortDateTime');
- MyWorksheet.WriteDateTime(13, 1, now, nfShortDateTime);
- MyWorksheet.WriteUTF8Text(14, 0, 'nfFmtDateTime, DM');
- MyWorksheet.WriteDateTime(14, 1, now, nfFmtDateTime, 'DM');
- MyWorksheet.WriteUTF8Text(15, 0, 'nfFmtDateTime, MY');
- MyWorksheet.WriteDateTime(15, 1, now, nfFmtDateTime, 'MY');
- MyWorksheet.WriteUTF8Text(16, 0, 'nfShortTimeAM');
- MyWorksheet.WriteDateTime(16, 1, now, nfShortTimeAM);
- MyWorksheet.WriteUTF8Text(17, 0, 'nfLongTimeAM');
- MyWorksheet.WriteDateTime(17, 1, now, nfLongTimeAM);
- MyWorksheet.WriteUTF8Text(18, 0, 'nfFmtDateTime, MS');
- MyWorksheet.WriteDateTime(18, 1, now, nfFmtDateTime, 'MS');
- MyWorksheet.WriteUTF8Text(19, 0, 'nfFmtDateTime, MSZ');
- MyWorksheet.WriteDateTime(19, 1, now, nfFmtDateTime, 'MSZ');
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDateTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDateTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, DM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'DM');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MY');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MY');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MS');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MS');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MSZ');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MSZ');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
+ MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
// Write formatted numbers
number := 12345.67890123456789;
- MyWorksheet.WriteUTF8Text(24, 1, '12345.67890123456789');
- MyWorksheet.WriteUTF8Text(24, 2, '-12345.67890123456789');
- MyWorksheet.WriteUTF8Text(25, 0, 'nfFixed, 0 decs');
- MyWorksheet.WriteNumber(25, 1, number, nfFixed, 0);
- MyWorksheet.WriteNumber(25, 2, -number, nfFixed, 0);
- MyWorksheet.WriteUTF8Text(26, 0, 'nfFixed, 2 decs');
- MyWorksheet.WriteNumber(26, 1, number, nfFixed, 2);
- MyWorksheet.WriteNumber(26, 2, -number, nfFixed, 2);
- MyWorksheet.WriteUTF8Text(27, 0, 'nfFixedTh, 0 decs');
- MyWorksheet.WriteNumber(27, 1, number, nfFixedTh, 0);
- MyWorksheet.WriteNumber(27, 2, -number, nfFixedTh, 0);
- MyWorksheet.WriteUTF8Text(28, 0, 'nfFixedTh, 2 decs');
- MyWorksheet.WriteNumber(28, 1, number, nfFixedTh, 2);
- MyWorksheet.WriteNumber(28, 2, -number, nfFixedTh, 2);
- MyWorksheet.WriteUTF8Text(29, 0, 'nfSci, 1 dec');
- MyWorksheet.WriteNumber(29, 1, number, nfSci);
- MyWorksheet.WriteNumber(29, 2, -number, nfSci);
- MyWorksheet.WriteNumber(29, 3, 1.0/number, nfSci);
- MyWorksheet.WriteNumber(29, 4, -1.0/number, nfSci);
- MyWorksheet.WriteUTF8Text(30, 0, 'nfExp, 2 decs');
- MyWorksheet.WriteNumber(30, 1, number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 2, -number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 3, 1.0/number, nfExp, 2);
- MyWorksheet.WriteNumber(30, 4, -1.0/number, nfExp, 2);
-
+ inc(r, 2);
+ MyWorksheet.WriteUTF8Text(r, 1, '12345.67890123456789');
+ MyWorksheet.WriteUTF8Text(r, 2, '-12345.67890123456789');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfGeneral');
+ MyWorksheet.WriteNumber(r, 1, number, nfGeneral);
+ MyWorksheet.WriteNumber(r, 2, -number, nfGeneral);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 1);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 2 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 2);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 2);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 3 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfSci, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfSci, 3);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 1);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 3);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 3);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "EUR "#,##0_);("EUR "#,##0)');
+ MyWorksheet.WriteDateTime(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"EUR "#,##0_);("EUR "#,##0)');
+ MyWorksheet.WriteDateTime(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"EUR "#,##0_);("EUR "#,##0)');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteDateTime(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteDateTime(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ inc(r, 2);
number := 1.333333333;
- MyWorksheet.WriteUTF8Text(35, 0, 'nfPercentage, 0 decs');
- MyWorksheet.WriteNumber(35, 1, number, nfPercentage, 0);
- MyWorksheet.WriteUTF8Text(36, 0, 'nfPercentage, 2 decs');
- MyWorksheet.WriteNumber(36, 1, number, nfPercentage, 2);
- MyWorksheet.WriteUTF8Text(37, 0, 'nfTimeInterval');
- MyWorksheet.WriteDateTime(37, 1, number, nfTimeInterval);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 1);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 3);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm:ss');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'H:M:s');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
// Set width of columns 0, 1 and 5
MyWorksheet.WriteColWidth(0, 25);
lCol.Width := 20;
MyWorksheet.WriteColInfo(1, lCol);
+ MyWorksheet.WriteColInfo(2, lCol);
+ MyWorksheet.WriteColWidth(3, 15);
+ MyWorksheet.WriteColWidth(4, 15);
lCol.Width := 5;
MyWorksheet.WriteColInfo(5, lCol);
diff --git a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
index ccd169e5d..8cd0a41f0 100644
--- a/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
+++ b/components/fpspreadsheet/examples/fpsgrid/fpsgrid.lpi
@@ -126,6 +126,7 @@
+
@@ -137,25 +138,24 @@
-
+
-
-
+
+
+
+
+
-
-
+
-
-
+
+
-
-
-
@@ -224,20 +224,20 @@
-
-
+
-
-
+
+
+
@@ -249,12 +249,10 @@
-
-
@@ -266,11 +264,11 @@
-
+
-
-
-
+
+
+
@@ -291,31 +289,31 @@
-
+
-
-
-
+
+
+
-
+
-
-
-
+
+
+
-
+
-
-
-
+
+
+
@@ -398,12 +396,10 @@
-
-
@@ -565,144 +561,136 @@
-
-
-
-
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
-
-
diff --git a/components/fpspreadsheet/examples/fpsgrid/mainform.lfm b/components/fpspreadsheet/examples/fpsgrid/mainform.lfm
index 3a75fecc5..7f8f2d2db 100644
--- a/components/fpspreadsheet/examples/fpsgrid/mainform.lfm
+++ b/components/fpspreadsheet/examples/fpsgrid/mainform.lfm
@@ -1,11 +1,11 @@
object Form1: TForm1
- Left = 370
- Height = 406
- Top = 258
- Width = 636
+ Left = 359
+ Height = 593
+ Top = 193
+ Width = 722
Caption = 'fpsGrid'
- ClientHeight = 386
- ClientWidth = 636
+ ClientHeight = 568
+ ClientWidth = 722
Menu = MainMenu1
OnActivate = FormActivate
OnCreate = FormCreate
@@ -13,19 +13,19 @@ object Form1: TForm1
LCLVersion = '1.3'
object Panel1: TPanel
Left = 0
- Height = 73
- Top = 313
- Width = 636
+ Height = 76
+ Top = 492
+ Width = 722
Align = alBottom
BevelOuter = bvNone
- ClientHeight = 73
- ClientWidth = 636
+ ClientHeight = 76
+ ClientWidth = 722
TabOrder = 0
object CbShowHeaders: TCheckBox
Left = 8
- Height = 19
+ Height = 24
Top = 11
- Width = 93
+ Width = 116
Caption = 'Show headers'
Checked = True
OnClick = CbShowHeadersClick
@@ -34,9 +34,9 @@ object Form1: TForm1
end
object CbShowGridLines: TCheckBox
Left = 8
- Height = 19
+ Height = 24
Top = 36
- Width = 100
+ Width = 125
Caption = 'Show grid lines'
Checked = True
OnClick = CbShowGridLinesClick
@@ -45,7 +45,7 @@ object Form1: TForm1
end
object EdFrozenCols: TSpinEdit
Left = 238
- Height = 23
+ Height = 28
Top = 8
Width = 52
OnChange = EdFrozenColsChange
@@ -53,7 +53,7 @@ object Form1: TForm1
end
object EdFrozenRows: TSpinEdit
Left = 238
- Height = 23
+ Height = 28
Top = 39
Width = 52
OnChange = EdFrozenRowsChange
@@ -61,18 +61,18 @@ object Form1: TForm1
end
object Label1: TLabel
Left = 152
- Height = 15
+ Height = 20
Top = 13
- Width = 62
+ Width = 77
Caption = 'Frozen cols:'
FocusControl = EdFrozenCols
ParentColor = False
end
object Label2: TLabel
Left = 153
- Height = 15
+ Height = 20
Top = 40
- Width = 66
+ Width = 82
Caption = 'Frozen rows:'
FocusControl = EdFrozenRows
ParentColor = False
@@ -80,9 +80,9 @@ object Form1: TForm1
end
object PageControl1: TPageControl
Left = 0
- Height = 260
+ Height = 439
Top = 53
- Width = 636
+ Width = 722
ActivePage = TabSheet1
Align = alClient
TabIndex = 0
@@ -90,13 +90,13 @@ object Form1: TForm1
OnChange = PageControl1Change
object TabSheet1: TTabSheet
Caption = 'Sheet1'
- ClientHeight = 232
- ClientWidth = 628
+ ClientHeight = 406
+ ClientWidth = 714
object sWorksheetGrid1: TsWorksheetGrid
Left = 0
- Height = 232
+ Height = 406
Top = 0
- Width = 628
+ Width = 714
FrozenCols = 0
FrozenRows = 0
Align = alClient
@@ -108,7 +108,7 @@ object Form1: TForm1
TitleStyle = tsNative
OnSelection = sWorksheetGrid1Selection
ColWidths = (
- 42
+ 56
64
)
end
@@ -118,7 +118,7 @@ object Form1: TForm1
Left = 0
Height = 26
Top = 0
- Width = 636
+ Width = 722
ButtonHeight = 24
Caption = 'ToolBar1'
EdgeBorders = []
@@ -163,7 +163,7 @@ object Form1: TForm1
Left = 0
Height = 27
Top = 26
- Width = 636
+ Width = 722
ButtonHeight = 23
Caption = 'FormatToolBar'
Images = ImageList1
@@ -185,19 +185,19 @@ object Form1: TForm1
end
object FontComboBox: TComboBox
Left = 24
- Height = 23
+ Height = 28
Top = 2
Width = 127
- ItemHeight = 15
+ ItemHeight = 20
OnSelect = FontComboBoxSelect
TabOrder = 0
end
object FontSizeComboBox: TComboBox
Left = 151
- Height = 23
+ Height = 28
Top = 2
Width = 48
- ItemHeight = 15
+ ItemHeight = 20
Items.Strings = (
'8'
'9'
diff --git a/components/fpspreadsheet/examples/fpsgrid/mainform.lrs b/components/fpspreadsheet/examples/fpsgrid/mainform.lrs
index 9d61fffa2..02a826a19 100644
--- a/components/fpspreadsheet/examples/fpsgrid/mainform.lrs
+++ b/components/fpspreadsheet/examples/fpsgrid/mainform.lrs
@@ -1,307 +1,308 @@
{ This is an automatically generated lazarus resource file }
LazarusResources.Add('TForm1','FORMDATA',[
- 'TPF0'#6'TForm1'#5'Form1'#4'Left'#3'r'#1#6'Height'#3#150#1#3'Top'#3#2#1#5'Wid'
- +'th'#3'|'#2#7'Caption'#6#7'fpsGrid'#12'ClientHeight'#3#130#1#11'ClientWidth'
- +#3'|'#2#4'Menu'#7#9'MainMenu1'#10'OnActivate'#7#12'FormActivate'#8'OnCreate'
+ 'TPF0'#6'TForm1'#5'Form1'#4'Left'#3'g'#1#6'Height'#3'Q'#2#3'Top'#3#193#0#5'Wi'
+ +'dth'#3#210#2#7'Caption'#6#7'fpsGrid'#12'ClientHeight'#3'8'#2#11'ClientWidth'
+ +#3#210#2#4'Menu'#7#9'MainMenu1'#10'OnActivate'#7#12'FormActivate'#8'OnCreate'
+#7#10'FormCreate'#8'ShowHint'#9#10'LCLVersion'#6#3'1.3'#0#6'TPanel'#6'Panel1'
- +#4'Left'#2#0#6'Height'#2'I'#3'Top'#3'9'#1#5'Width'#3'|'#2#5'Align'#7#8'alBot'
- +'tom'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'I'#11'ClientWidth'#3'|'#2
- +#8'TabOrder'#2#0#0#9'TCheckBox'#13'CbShowHeaders'#4'Left'#2#8#6'Height'#2#19
- +#3'Top'#2#11#5'Width'#2']'#7'Caption'#6#12'Show headers'#7'Checked'#9#7'OnCl'
- +'ick'#7#18'CbShowHeadersClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#0#0#0#9
- +'TCheckBox'#15'CbShowGridLines'#4'Left'#2#8#6'Height'#2#19#3'Top'#2'$'#5'Wid'
- +'th'#2'd'#7'Caption'#6#15'Show grid lines'#7'Checked'#9#7'OnClick'#7#20'CbSh'
- +'owGridLinesClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#1#0#0#9'TSpinEdit'
- +#12'EdFrozenCols'#4'Left'#3#238#0#6'Height'#2#23#3'Top'#2#8#5'Width'#2'4'#8
- +'OnChange'#7#18'EdFrozenColsChange'#8'TabOrder'#2#2#0#0#9'TSpinEdit'#12'EdFr'
- +'ozenRows'#4'Left'#3#238#0#6'Height'#2#23#3'Top'#2''''#5'Width'#2'4'#8'OnCha'
- +'nge'#7#18'EdFrozenRowsChange'#8'TabOrder'#2#3#0#0#6'TLabel'#6'Label1'#4'Lef'
- +'t'#3#152#0#6'Height'#2#15#3'Top'#2#13#5'Width'#2'>'#7'Caption'#6#12'Frozen '
- +'cols:'#12'FocusControl'#7#12'EdFrozenCols'#11'ParentColor'#8#0#0#6'TLabel'#6
- +'Label2'#4'Left'#3#153#0#6'Height'#2#15#3'Top'#2'('#5'Width'#2'B'#7'Caption'
- +#6#12'Frozen rows:'#12'FocusControl'#7#12'EdFrozenRows'#11'ParentColor'#8#0#0
- +#0#12'TPageControl'#12'PageControl1'#4'Left'#2#0#6'Height'#3#4#1#3'Top'#2'5'
- +#5'Width'#3'|'#2#10'ActivePage'#7#9'TabSheet1'#5'Align'#7#8'alClient'#8'TabI'
- +'ndex'#2#0#8'TabOrder'#2#1#8'OnChange'#7#18'PageControl1Change'#0#9'TTabShee'
- +'t'#9'TabSheet1'#7'Caption'#6#6'Sheet1'#12'ClientHeight'#3#232#0#11'ClientWi'
- +'dth'#3't'#2#0#15'TsWorksheetGrid'#15'sWorksheetGrid1'#4'Left'#2#0#6'Height'
- +#3#232#0#3'Top'#2#0#5'Width'#3't'#2#10'FrozenCols'#2#0#10'FrozenRows'#2#0#5
- +'Align'#7#8'alClient'#8'ColCount'#2#2#14'ExtendedSelect'#8#7'Options'#11#15
- +'goFixedVertLine'#15'goFixedHorzLine'#10'goVertLine'#10'goHorzLine'#13'goRan'
- +'geSelect'#11'goRowSizing'#11'goColSizing'#15'goThumbTracking'#14'goSmoothSc'
- +'roll'#16'goFixedColSizing'#0#8'RowCount'#2#2#8'TabOrder'#2#0#10'TitleStyle'
- +#7#8'tsNative'#11'OnSelection'#7#24'sWorksheetGrid1Selection'#9'ColWidths'#1
- +#2'*'#2'@'#0#0#0#0#0#8'TToolBar'#8'ToolBar1'#4'Left'#2#0#6'Height'#2#26#3'To'
- +'p'#2#0#5'Width'#3'|'#2#12'ButtonHeight'#2#24#7'Caption'#6#8'ToolBar1'#11'Ed'
- +'geBorders'#11#0#6'Images'#7#10'ImageList1'#8'TabOrder'#2#2#0#11'TToolButton'
- +#11'ToolButton1'#4'Left'#2#1#3'Top'#2#0#6'Action'#7#6'AcOpen'#0#0#11'TToolBu'
- +'tton'#11'ToolButton2'#4'Left'#2#24#3'Top'#2#0#6'Action'#7#8'AcSaveAs'#0#0#11
- +'TToolButton'#11'ToolButton3'#4'Left'#2'P'#3'Top'#2#0#6'Action'#7#6'AcQuit'#0
- +#0#11'TToolButton'#11'ToolButton5'#4'Left'#2'/'#3'Top'#2#0#5'Width'#2#5#7'Ca'
- +'ption'#6#11'ToolButton5'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#11'T'
- +'oolButton4'#4'Left'#2'4'#3'Top'#2#0#6'Action'#7#6'AcEdit'#0#0#11'TToolButto'
- +'n'#11'ToolButton6'#4'Left'#2'K'#3'Top'#2#0#5'Width'#2#5#7'Caption'#6#11'Too'
- +'lButton6'#5'Style'#7#10'tbsDivider'#0#0#0#8'TToolBar'#13'FormatToolBar'#4'L'
- +'eft'#2#0#6'Height'#2#27#3'Top'#2#26#5'Width'#3'|'#2#12'ButtonHeight'#2#23#7
- +'Caption'#6#13'FormatToolBar'#6'Images'#7#10'ImageList1'#8'TabOrder'#2#3#0#11
- +'TToolButton'#12'ToolButton10'#4'Left'#3'('#1#3'Top'#2#2#6'Action'#7#11'AcLe'
- +'ftAlign'#0#0#11'TToolButton'#12'ToolButton12'#4'Left'#3'?'#1#3'Top'#2#2#6'A'
- +'ction'#7#16'AcHorCenterAlign'#0#0#11'TToolButton'#12'ToolButton13'#4'Left'#3
- +'V'#1#3'Top'#2#2#6'Action'#7#12'AcRightAlign'#0#0#9'TComboBox'#12'FontComboB'
- +'ox'#4'Left'#2#24#6'Height'#2#23#3'Top'#2#2#5'Width'#2#127#10'ItemHeight'#2
- +#15#8'OnSelect'#7#18'FontComboBoxSelect'#8'TabOrder'#2#0#0#0#9'TComboBox'#16
- +'FontSizeComboBox'#4'Left'#3#151#0#6'Height'#2#23#3'Top'#2#2#5'Width'#2'0'#10
- +'ItemHeight'#2#15#13'Items.Strings'#1#6#1'8'#6#1'9'#6#2'10'#6#2'11'#6#2'12'#6
- +#2'14'#6#2'16'#6#2'18'#6#2'20'#6#2'24'#0#8'OnSelect'#7#22'FontSizeComboBoxSe'
- +'lect'#8'TabOrder'#2#1#0#0#11'TToolButton'#11'ToolButton7'#4'Left'#3#199#0#3
- +'Top'#2#2#6'Action'#7#10'AcFontBold'#0#0#11'TToolButton'#11'ToolButton8'#4'L'
- +'eft'#3#222#0#3'Top'#2#2#6'Action'#7#12'AcFontItalic'#0#0#11'TToolButton'#11
- +'ToolButton9'#4'Left'#3#245#0#3'Top'#2#2#6'Action'#7#15'AcFontUnderline'#0#0
- +#11'TToolButton'#12'ToolButton11'#4'Left'#3#12#1#3'Top'#2#2#6'Action'#7#15'A'
- +'cFontStrikeout'#0#0#11'TToolButton'#12'ToolButton14'#4'Left'#3'#'#1#3'Top'#2
- +#2#5'Width'#2#5#7'Caption'#6#12'ToolButton14'#5'Style'#7#10'tbsDivider'#0#0
- +#11'TToolButton'#12'ToolButton15'#4'Left'#3'm'#1#3'Top'#2#2#5'Width'#2#5#7'C'
- +'aption'#6#12'ToolButton15'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#12
- +'ToolButton16'#4'Left'#3'r'#1#3'Top'#2#2#6'Action'#7#11'AcVAlignTop'#0#0#11
- +'TToolButton'#12'ToolButton17'#4'Left'#3#137#1#3'Top'#2#2#6'Action'#7#14'AcV'
- ,'AlignCenter'#0#0#11'TToolButton'#12'ToolButton18'#4'Left'#3#160#1#3'Top'#2#2
- +#6'Action'#7#14'AcVAlignBottom'#0#0#11'TToolButton'#12'ToolButton19'#4'Left'
- +#3#183#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButton19'#5'Style'#7#10
- +'tbsDivider'#0#0#11'TToolButton'#9'TbBorders'#4'Left'#3#188#1#3'Top'#2#2#6'A'
- +'ction'#7#12'AcBorderNone'#12'DropdownMenu'#7#16'BordersPopupMenu'#5'Style'#7
- +#11'tbsDropDown'#0#0#9'TColorBox'#17'CbBackgroundColor'#4'Left'#3#223#1#6'He'
- +'ight'#2#22#3'Top'#2#2#5'Width'#3#132#0#5'Style'#11#13'cbPrettyNames'#14'cbC'
- +'ustomColors'#0#11'OnGetColors'#7#26'CbBackgroundColorGetColors'#10'ItemHeig'
- +'ht'#2#16#8'OnSelect'#7#23'CbBackgroundColorSelect'#8'TabOrder'#2#2#0#0#11'T'
- +'ToolButton'#12'ToolButton21'#4'Left'#2#1#3'Top'#2#2#6'Action'#7#6'AcFont'#0
- +#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4'.xls'#6'Filter'#6#192
- +'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlxs|Libre'
- +'Office/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (pipes) (.wikitable_p'
- +'ipes)|.wikitable_pipes|All files (*.*)|*.*'#7'Options'#11#20'ofExtensionDif'
- +'ferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#2'@'#3'top'#3#176#0#0
- +#0#11'TSaveDialog'#11'SaveDialog1'#10'DefaultExt'#6#4'.xls'#6'Filter'#6#185
- +'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlsx|Libre'
- +'Office/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (wikimedia) (.wikitab'
- +'le_wikimedia)|*.wikitable_wikimedia'#7'Options'#11#17'ofOverwritePrompt'#20
- +'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#3#176#0
- +#3'top'#3#176#0#0#0#9'TMainMenu'#9'MainMenu1'#6'Images'#7#10'ImageList1'#4'l'
- +'eft'#3' '#1#3'top'#2'@'#0#9'TMenuItem'#7'mnuFile'#7'Caption'#6#5'&File'#0#9
- +'TMenuItem'#7'mnuOpen'#6'Action'#7#6'AcOpen'#11'Bitmap.Data'#10':'#4#0#0'6'#4
- +#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0
- +#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0','#134#216#0'-'#136#216#247'-'#135
- +#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136
- +#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#135#216#247'-'#136
- +#216#247','#134#216#0#255#255#255#0#255#255#255#0'3'#142#217#251#220#240#250
- +#255#152#225#246#255#149#224#246#255#146#223#246#255#142#222#245#255#137#220
- +#245#255#133#218#244#255#128#217#244#255'z'#215#243#255't'#213#243#255'p'#211
- +#242#255#194#234#248#255'5'#148#218#255#255#255#255#0#255#255#255#0'5'#148
- +#218#247#239#250#254#255#147#229#248#255#143#228#248#255#137#227#248#255#130
- +#225#247#255'z'#223#247#255'q'#222#246#255'g'#219#245#255'['#216#244#255'M'
- +#212#243#255'@'#209#242#255#202#242#251#255'5'#148#218#255#255#255#255#0#255
- +#255#255#0'6'#154#218#248#242#250#253#255#148#230#248#255#146#229#248#255#144
- +#229#248#255#139#227#248#255#134#226#247#255#127#225#247#255'w'#222#246#255
- +'l'#220#246#255'^'#217#244#255'O'#213#243#255#204#242#251#255'5'#148#218#255
- +#255#255#255#0#255#255#255#0'6'#161#218#249#246#252#254#255#148#229#248#255
- +#147#229#248#255#147#229#248#255#145#229#248#255#147#219#233#255#147#215#227
- +#255#147#210#220#255#144#206#215#255#140#200#207#255#134#193#198#255#201#216
- +#214#255'5'#148#218#255#197'tD'#232#202#127'S'#241'7'#166#218#250#254#255#255
- +#255#248#253#255#255#246#253#255#255#245#252#255#255#243#252#254#255#154#228
- +#244#255#154#230#247#255#155#230#246#255#157#229#245#255#158#229#245#255#159
- +#229#244#255#218#243#248#255'5'#148#218#255#253#244#238#255#202#128'T'#249'5'
- +#171#218#250#232#246#251#255'p'#188#231#255'U'#170#226#255'M'#165#224#255#145
- +#201#235#255#250#243#239#255#253#254#253#255#255#253#252#255#255#253#252#255
- +#254#253#252#255#254#252#251#255#254#254#253#255'5'#148#218#255#239#242#232
- +#255#206#129'V'#255'6'#170#218#242#241#250#253#255#148#222#245#255#147#220
- +#244#255'd'#188#233#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148
- +#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148
- +#218#255#251#246#239#255#204#131'U'#254'5'#175#218#240#247#252#254#255#142
- +#228#248#255#145#222#245#255#159#224#245#255#172#225#246#255#202#132'R'#255
- +#255#247#241#255#255#233#217#255#255#234#219#255#255#233#217#255#255#231#215
- +#255#255#229#210#255#255#226#203#255#255#247#241#255#203#133'U'#254'6'#179
- +#218#248#253#254#254#255#254#255#255#255#254#254#255#255#253#254#255#255#254
- +#255#255#255#228#186#145#255#255#247#240#255#255#231#213#255#253#231#214#255
- +#253#230#212#255#252#228#208#255#251#227#203#255#250#220#194#255#254#243#232
- +#255#204#134'V'#254'4'#180#217#208'^'#194#225#250'`'#195#226#250'`'#195#226
- +#250'`'#195#226#250'_'#195#226#250#228#187#145#255#255#247#242#255#254#231
- +#213#255#254#231#213#255#253#229#209#255#250#224#202#255#249#222#196#255#247
- +#217#188#255#253#242#231#255#204#135'W'#254#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187#146#255#254#247
- +#241#255#252#229#210#255#252#228#209#255#251#226#204#255#249#221#196#255#246
- +#215#187#255#243#209#175#255#250#239#228#255#204#135'X'#254#255#255#255#0#255
- ,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187
- +#146#255#254#246#240#255#252#226#205#255#252#227#205#255#250#223#200#255#247
- +#217#188#255#245#233#221#255#250#243#235#255#251#248#243#255#202#131'S'#254
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#228#187#147#255#254#245#237#255#252#222#197#255#251#224#199#255
- +#249#220#194#255#245#211#180#255#254#249#243#255#250#226#196#255#236#193#147
- +#255#195'}H'#147#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#229#190#150#255#255#255#254#255#253#243#233#255#253
- +#243#234#255#252#242#232#255#250#239#227#255#250#242#231#255#234#187#136#255
- +#207#133'U'#179#180'i='#12#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#234#195#157#255#230#191#150#255#228#187
- +#146#255#228#187#146#255#209#160'l'#245#208#158'm'#246#204#150'_'#218#196'yB'
- +'~'#178'g<'#9#255#255#255#0#7'OnClick'#7#13'acOpenExecute'#0#0#9'TMenuItem'#9
- +'mnuSaveAs'#6'Action'#7#8'AcSaveAs'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'
- +#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0
- +'d'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#186'j6'#0#185'i5'#181#184'i5'#238#183'h5'
- +#255#181'h5'#255#180'g4'#255#178'f4'#255#176'e3'#255#174'd3'#255#172'c2'#255
- +#170'b2'#255#169'a2'#255#168'`1'#255#167'`1'#254#166'`1'#241#168'a1'#196#186
- +'j5'#222#235#198#173#255#234#197#173#255#254#251#248#255#254#251#248#255#254
- +#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255
- +#254#251#248#255#254#251#248#255#254#251#248#255#200#154'|'#255#199#152'y'
- +#255#167'`1'#237#186'k7'#254#237#202#179#255#224#162'z'#255#254#250#247#255
- +'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
- +'b'#192#136#255'b'#192#136#255'b'#192#136#255#253#249#246#255#202#141'e'#255
- +#201#155'|'#255#167'`1'#254#187'l8'#255#238#204#182#255#225#162'z'#255#254
- +#250#247#255#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194#255
- +#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194#255#253#249#246
- +#255#205#144'h'#255#204#158#129#255#168'a2'#255#187'k8'#255#239#206#184#255
- +#225#162'y'#255#254#250#247#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
- +'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
- +#253#249#246#255#207#147'j'#255#206#163#132#255#170'a2'#255#186'j6'#255#239
- +#208#187#255#226#162'z'#255#254#251#248#255#254#251#248#255#254#251#248#255
+ +#4'Left'#2#0#6'Height'#2'L'#3'Top'#3#236#1#5'Width'#3#210#2#5'Align'#7#8'alB'
+ +'ottom'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'L'#11'ClientWidth'#3
+ +#210#2#8'TabOrder'#2#0#0#9'TCheckBox'#13'CbShowHeaders'#4'Left'#2#8#6'Height'
+ +#2#24#3'Top'#2#11#5'Width'#2't'#7'Caption'#6#12'Show headers'#7'Checked'#9#7
+ +'OnClick'#7#18'CbShowHeadersClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#0#0
+ +#0#9'TCheckBox'#15'CbShowGridLines'#4'Left'#2#8#6'Height'#2#24#3'Top'#2'$'#5
+ +'Width'#2'}'#7'Caption'#6#15'Show grid lines'#7'Checked'#9#7'OnClick'#7#20'C'
+ +'bShowGridLinesClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#1#0#0#9'TSpinEdi'
+ +'t'#12'EdFrozenCols'#4'Left'#3#238#0#6'Height'#2#28#3'Top'#2#8#5'Width'#2'4'
+ +#8'OnChange'#7#18'EdFrozenColsChange'#8'TabOrder'#2#2#0#0#9'TSpinEdit'#12'Ed'
+ +'FrozenRows'#4'Left'#3#238#0#6'Height'#2#28#3'Top'#2''''#5'Width'#2'4'#8'OnC'
+ +'hange'#7#18'EdFrozenRowsChange'#8'TabOrder'#2#3#0#0#6'TLabel'#6'Label1'#4'L'
+ +'eft'#3#152#0#6'Height'#2#20#3'Top'#2#13#5'Width'#2'M'#7'Caption'#6#12'Froze'
+ +'n cols:'#12'FocusControl'#7#12'EdFrozenCols'#11'ParentColor'#8#0#0#6'TLabel'
+ +#6'Label2'#4'Left'#3#153#0#6'Height'#2#20#3'Top'#2'('#5'Width'#2'R'#7'Captio'
+ +'n'#6#12'Frozen rows:'#12'FocusControl'#7#12'EdFrozenRows'#11'ParentColor'#8
+ +#0#0#0#12'TPageControl'#12'PageControl1'#4'Left'#2#0#6'Height'#3#183#1#3'Top'
+ +#2'5'#5'Width'#3#210#2#10'ActivePage'#7#9'TabSheet1'#5'Align'#7#8'alClient'#8
+ +'TabIndex'#2#0#8'TabOrder'#2#1#8'OnChange'#7#18'PageControl1Change'#0#9'TTab'
+ +'Sheet'#9'TabSheet1'#7'Caption'#6#6'Sheet1'#12'ClientHeight'#3#150#1#11'Clie'
+ +'ntWidth'#3#202#2#0#15'TsWorksheetGrid'#15'sWorksheetGrid1'#4'Left'#2#0#6'He'
+ +'ight'#3#150#1#3'Top'#2#0#5'Width'#3#202#2#10'FrozenCols'#2#0#10'FrozenRows'
+ +#2#0#5'Align'#7#8'alClient'#8'ColCount'#2#2#14'ExtendedSelect'#8#7'Options'
+ +#11#15'goFixedVertLine'#15'goFixedHorzLine'#10'goVertLine'#10'goHorzLine'#13
+ +'goRangeSelect'#11'goRowSizing'#11'goColSizing'#15'goThumbTracking'#14'goSmo'
+ +'othScroll'#16'goFixedColSizing'#0#8'RowCount'#2#2#8'TabOrder'#2#0#10'TitleS'
+ +'tyle'#7#8'tsNative'#11'OnSelection'#7#24'sWorksheetGrid1Selection'#9'ColWid'
+ +'ths'#1#2'8'#2'@'#0#0#0#0#0#8'TToolBar'#8'ToolBar1'#4'Left'#2#0#6'Height'#2
+ +#26#3'Top'#2#0#5'Width'#3#210#2#12'ButtonHeight'#2#24#7'Caption'#6#8'ToolBar'
+ +'1'#11'EdgeBorders'#11#0#6'Images'#7#10'ImageList1'#8'TabOrder'#2#2#0#11'TTo'
+ +'olButton'#11'ToolButton1'#4'Left'#2#1#3'Top'#2#0#6'Action'#7#6'AcOpen'#0#0
+ +#11'TToolButton'#11'ToolButton2'#4'Left'#2#24#3'Top'#2#0#6'Action'#7#8'AcSav'
+ +'eAs'#0#0#11'TToolButton'#11'ToolButton3'#4'Left'#2'P'#3'Top'#2#0#6'Action'#7
+ +#6'AcQuit'#0#0#11'TToolButton'#11'ToolButton5'#4'Left'#2'/'#3'Top'#2#0#5'Wid'
+ +'th'#2#5#7'Caption'#6#11'ToolButton5'#5'Style'#7#10'tbsDivider'#0#0#11'TTool'
+ +'Button'#11'ToolButton4'#4'Left'#2'4'#3'Top'#2#0#6'Action'#7#6'AcEdit'#0#0#11
+ +'TToolButton'#11'ToolButton6'#4'Left'#2'K'#3'Top'#2#0#5'Width'#2#5#7'Caption'
+ +#6#11'ToolButton6'#5'Style'#7#10'tbsDivider'#0#0#0#8'TToolBar'#13'FormatTool'
+ +'Bar'#4'Left'#2#0#6'Height'#2#27#3'Top'#2#26#5'Width'#3#210#2#12'ButtonHeigh'
+ +'t'#2#23#7'Caption'#6#13'FormatToolBar'#6'Images'#7#10'ImageList1'#8'TabOrde'
+ +'r'#2#3#0#11'TToolButton'#12'ToolButton10'#4'Left'#3'('#1#3'Top'#2#2#6'Actio'
+ +'n'#7#11'AcLeftAlign'#0#0#11'TToolButton'#12'ToolButton12'#4'Left'#3'?'#1#3
+ +'Top'#2#2#6'Action'#7#16'AcHorCenterAlign'#0#0#11'TToolButton'#12'ToolButton'
+ +'13'#4'Left'#3'V'#1#3'Top'#2#2#6'Action'#7#12'AcRightAlign'#0#0#9'TComboBox'
+ +#12'FontComboBox'#4'Left'#2#24#6'Height'#2#28#3'Top'#2#2#5'Width'#2#127#10'I'
+ +'temHeight'#2#20#8'OnSelect'#7#18'FontComboBoxSelect'#8'TabOrder'#2#0#0#0#9
+ +'TComboBox'#16'FontSizeComboBox'#4'Left'#3#151#0#6'Height'#2#28#3'Top'#2#2#5
+ +'Width'#2'0'#10'ItemHeight'#2#20#13'Items.Strings'#1#6#1'8'#6#1'9'#6#2'10'#6
+ +#2'11'#6#2'12'#6#2'14'#6#2'16'#6#2'18'#6#2'20'#6#2'24'#0#8'OnSelect'#7#22'Fo'
+ +'ntSizeComboBoxSelect'#8'TabOrder'#2#1#0#0#11'TToolButton'#11'ToolButton7'#4
+ +'Left'#3#199#0#3'Top'#2#2#6'Action'#7#10'AcFontBold'#0#0#11'TToolButton'#11
+ +'ToolButton8'#4'Left'#3#222#0#3'Top'#2#2#6'Action'#7#12'AcFontItalic'#0#0#11
+ +'TToolButton'#11'ToolButton9'#4'Left'#3#245#0#3'Top'#2#2#6'Action'#7#15'AcFo'
+ +'ntUnderline'#0#0#11'TToolButton'#12'ToolButton11'#4'Left'#3#12#1#3'Top'#2#2
+ +#6'Action'#7#15'AcFontStrikeout'#0#0#11'TToolButton'#12'ToolButton14'#4'Left'
+ +#3'#'#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButton14'#5'Style'#7#10
+ +'tbsDivider'#0#0#11'TToolButton'#12'ToolButton15'#4'Left'#3'm'#1#3'Top'#2#2#5
+ +'Width'#2#5#7'Caption'#6#12'ToolButton15'#5'Style'#7#10'tbsDivider'#0#0#11'T'
+ +'ToolButton'#12'ToolButton16'#4'Left'#3'r'#1#3'Top'#2#2#6'Action'#7#11'AcVAl'
+ +'ignTop'#0#0#11'TToolButton'#12'ToolButton17'#4'Left'#3#137#1#3'Top'#2#2#6'A'
+ ,'ction'#7#14'AcVAlignCenter'#0#0#11'TToolButton'#12'ToolButton18'#4'Left'#3
+ +#160#1#3'Top'#2#2#6'Action'#7#14'AcVAlignBottom'#0#0#11'TToolButton'#12'Tool'
+ +'Button19'#4'Left'#3#183#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButto'
+ +'n19'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#9'TbBorders'#4'Left'#3
+ +#188#1#3'Top'#2#2#6'Action'#7#12'AcBorderNone'#12'DropdownMenu'#7#16'Borders'
+ +'PopupMenu'#5'Style'#7#11'tbsDropDown'#0#0#9'TColorBox'#17'CbBackgroundColor'
+ +#4'Left'#3#223#1#6'Height'#2#22#3'Top'#2#2#5'Width'#3#132#0#5'Style'#11#13'c'
+ +'bPrettyNames'#14'cbCustomColors'#0#11'OnGetColors'#7#26'CbBackgroundColorGe'
+ +'tColors'#10'ItemHeight'#2#16#8'OnSelect'#7#23'CbBackgroundColorSelect'#8'Ta'
+ +'bOrder'#2#2#0#0#11'TToolButton'#12'ToolButton21'#4'Left'#2#1#3'Top'#2#2#6'A'
+ +'ction'#7#6'AcFont'#0#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4
+ +'.xls'#6'Filter'#6#192'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet'
+ +' (*.xlsx)|*.xlxs|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable'
+ +' (pipes) (.wikitable_pipes)|.wikitable_pipes|All files (*.*)|*.*'#7'Options'
+ +#11#20'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#2
+ +'@'#3'top'#3#176#0#0#0#11'TSaveDialog'#11'SaveDialog1'#10'DefaultExt'#6#4'.x'
+ +'ls'#6'Filter'#6#185'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet ('
+ +'*.xlsx)|*.xlsx|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable ('
+ +'wikimedia) (.wikitable_wikimedia)|*.wikitable_wikimedia'#7'Options'#11#17'o'
+ +'fOverwritePrompt'#20'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDeta'
+ +'il'#0#4'left'#3#176#0#3'top'#3#176#0#0#0#9'TMainMenu'#9'MainMenu1'#6'Images'
+ +#7#10'ImageList1'#4'left'#3' '#1#3'top'#2'@'#0#9'TMenuItem'#7'mnuFile'#7'Cap'
+ +'tion'#6#5'&File'#0#9'TMenuItem'#7'mnuOpen'#6'Action'#7#6'AcOpen'#11'Bitmap.'
+ +'Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16
+ +#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0','#134#216
+ +#0'-'#136#216#247'-'#135#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247
+ +'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247
+ +'-'#135#216#247'-'#136#216#247','#134#216#0#255#255#255#0#255#255#255#0'3'
+ +#142#217#251#220#240#250#255#152#225#246#255#149#224#246#255#146#223#246#255
+ +#142#222#245#255#137#220#245#255#133#218#244#255#128#217#244#255'z'#215#243
+ +#255't'#213#243#255'p'#211#242#255#194#234#248#255'5'#148#218#255#255#255#255
+ +#0#255#255#255#0'5'#148#218#247#239#250#254#255#147#229#248#255#143#228#248
+ +#255#137#227#248#255#130#225#247#255'z'#223#247#255'q'#222#246#255'g'#219#245
+ +#255'['#216#244#255'M'#212#243#255'@'#209#242#255#202#242#251#255'5'#148#218
+ +#255#255#255#255#0#255#255#255#0'6'#154#218#248#242#250#253#255#148#230#248
+ +#255#146#229#248#255#144#229#248#255#139#227#248#255#134#226#247#255#127#225
+ +#247#255'w'#222#246#255'l'#220#246#255'^'#217#244#255'O'#213#243#255#204#242
+ +#251#255'5'#148#218#255#255#255#255#0#255#255#255#0'6'#161#218#249#246#252
+ +#254#255#148#229#248#255#147#229#248#255#147#229#248#255#145#229#248#255#147
+ +#219#233#255#147#215#227#255#147#210#220#255#144#206#215#255#140#200#207#255
+ +#134#193#198#255#201#216#214#255'5'#148#218#255#197'tD'#232#202#127'S'#241'7'
+ +#166#218#250#254#255#255#255#248#253#255#255#246#253#255#255#245#252#255#255
+ +#243#252#254#255#154#228#244#255#154#230#247#255#155#230#246#255#157#229#245
+ +#255#158#229#245#255#159#229#244#255#218#243#248#255'5'#148#218#255#253#244
+ +#238#255#202#128'T'#249'5'#171#218#250#232#246#251#255'p'#188#231#255'U'#170
+ +#226#255'M'#165#224#255#145#201#235#255#250#243#239#255#253#254#253#255#255
+ +#253#252#255#255#253#252#255#254#253#252#255#254#252#251#255#254#254#253#255
+ +'5'#148#218#255#239#242#232#255#206#129'V'#255'6'#170#218#242#241#250#253#255
+ +#148#222#245#255#147#220#244#255'd'#188#233#255'5'#148#218#255'5'#148#218#255
+ +'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255
+ +'5'#148#218#255'5'#148#218#255#251#246#239#255#204#131'U'#254'5'#175#218#240
+ +#247#252#254#255#142#228#248#255#145#222#245#255#159#224#245#255#172#225#246
+ +#255#202#132'R'#255#255#247#241#255#255#233#217#255#255#234#219#255#255#233
+ +#217#255#255#231#215#255#255#229#210#255#255#226#203#255#255#247#241#255#203
+ +#133'U'#254'6'#179#218#248#253#254#254#255#254#255#255#255#254#254#255#255
+ +#253#254#255#255#254#255#255#255#228#186#145#255#255#247#240#255#255#231#213
+ +#255#253#231#214#255#253#230#212#255#252#228#208#255#251#227#203#255#250#220
+ +#194#255#254#243#232#255#204#134'V'#254'4'#180#217#208'^'#194#225#250'`'#195
+ +#226#250'`'#195#226#250'`'#195#226#250'_'#195#226#250#228#187#145#255#255#247
+ +#242#255#254#231#213#255#254#231#213#255#253#229#209#255#250#224#202#255#249
+ +#222#196#255#247#217#188#255#253#242#231#255#204#135'W'#254#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187
+ +#146#255#254#247#241#255#252#229#210#255#252#228#209#255#251#226#204#255#249
+ +#221#196#255#246#215#187#255#243#209#175#255#250#239#228#255#204#135'X'#254
+ ,#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#228#187#146#255#254#246#240#255#252#226#205#255#252#227#205#255
+ +#250#223#200#255#247#217#188#255#245#233#221#255#250#243#235#255#251#248#243
+ +#255#202#131'S'#254#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#228#187#147#255#254#245#237#255#252#222#197#255
+ +#251#224#199#255#249#220#194#255#245#211#180#255#254#249#243#255#250#226#196
+ +#255#236#193#147#255#195'}H'#147#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#229#190#150#255#255#255#254#255
+ +#253#243#233#255#253#243#234#255#252#242#232#255#250#239#227#255#250#242#231
+ +#255#234#187#136#255#207#133'U'#179#180'i='#12#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#234#195#157#255#230
+ +#191#150#255#228#187#146#255#228#187#146#255#209#160'l'#245#208#158'm'#246
+ +#204#150'_'#218#196'yB~'#178'g<'#9#255#255#255#0#7'OnClick'#7#13'acOpenExecu'
+ +'te'#0#0#9'TMenuItem'#9'mnuSaveAs'#6'Action'#7#8'AcSaveAs'#11'Bitmap.Data'#10
+ +':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0
+ +' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#186'j6'#0#185'i5'#181
+ +#184'i5'#238#183'h5'#255#181'h5'#255#180'g4'#255#178'f4'#255#176'e3'#255#174
+ +'d3'#255#172'c2'#255#170'b2'#255#169'a2'#255#168'`1'#255#167'`1'#254#166'`1'
+ +#241#168'a1'#196#186'j5'#222#235#198#173#255#234#197#173#255#254#251#248#255
+#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248
- +#255#254#251#248#255#254#251#248#255#211#150'm'#255#210#167#138#255#171'b2'
- +#255#187'j6'#255#240#210#190#255#226#163'z'#255#226#163'z'#255#225#163'z'#255
- +#226#163'{'#255#225#163'{'#255#224#161'x'#255#222#159'w'#255#221#159'v'#255
- +#220#157't'#255#217#155'r'#255#216#153'q'#255#214#153'p'#255#213#171#142#255
- +#173'c3'#255#187'j6'#255#242#213#194#255#227#163'z'#255#227#163'z'#255#226
- +#163'{'#255#226#163'{'#255#226#164'{'#255#225#162'y'#255#224#161'x'#255#222
- +#160'w'#255#222#158'u'#255#220#157't'#255#218#155's'#255#217#155's'#255#218
- +#176#149#255#175'd3'#255#187'j6'#255#242#216#197#255#227#164'{'#255#227#163
- +'z'#255#227#164'z'#255#226#164'{'#255#226#163'{'#255#225#163'{'#255#225#162
- +'y'#255#223#160'w'#255#222#159'v'#255#221#158't'#255#219#156'r'#255#220#157
- +'t'#255#221#181#154#255#177'e4'#255#187'k6'#255#244#217#199#255#230#166'}'
- +#255#200#140'd'#255#201#141'e'#255#201#142'g'#255#203#146'l'#255#203#146'm'
- +#255#202#144'i'#255#200#140'e'#255#200#140'd'#255#200#140'd'#255#200#140'd'
- +#255#218#156't'#255#225#186#159#255#179'f4'#255#187'k6'#254#244#220#201#255
- +#231#167'}'#255#249#236#225#255#249#236#225#255#249#237#227#255#252#244#238
- +#255#253#250#247#255#253#247#243#255#250#237#229#255#247#231#219#255#247#229
- +#217#255#246#229#216#255#222#160'w'#255#228#190#164#255#180'g4'#255#188'k6'
- +#250#245#221#204#255#231#168'~'#255#250#240#232#255#250#240#232#255#201#141
- +'f'#255#250#240#233#255#253#248#243#255#254#250#248#255#252#244#239#255#249
- +#233#223#255#247#231#219#255#247#229#217#255#224#162'x'#255#231#194#169#255
- +#182'h5'#255#188'k6'#240#246#223#208#255#232#168'~'#255#252#246#241#255#252
- +#246#241#255#200#140'd'#255#250#241#233#255#251#244#238#255#253#250#247#255
- +#253#249#246#255#250#240#232#255#248#232#221#255#247#230#219#255#225#163'z'
- +#255#239#213#195#255#183'i5'#254#188'k6'#216#246#223#209#255#233#170#128#255
- +#254#250#246#255#253#250#246#255#200#140'd'#255#251#243#238#255#251#241#234
- +#255#252#246#242#255#254#251#248#255#252#246#241#255#249#236#226#255#248#231
- +#219#255#238#208#186#255#236#208#189#255#187'p>'#248#188'k6'#155#246#224#209
- +#255#247#224#209#255#254#251#248#255#254#251#247#255#253#249#246#255#252#245
- +#240#255#250#240#234#255#251#242#237#255#253#249#246#255#253#250#247#255#251
- +#241#235#255#248#233#223#254#236#208#189#251#201#137'^'#236#181'i5c'#188'k6q'
- +#188'k6'#144#188'k6'#204#188'k6'#238#188'k6'#250#187'k6'#254#187'k6'#255#187
- ,'j6'#255#187'j6'#255#188'l9'#255#189'n;'#255#187'm:'#255#187'k8'#239#187'p>'
- +#203#182'i5T'#255#255#255#0#7'OnClick'#7#15'acSaveAsExecute'#0#0#9'TMenuItem'
- +#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#7'mnuQuit'#6'Action'#7#6'Ac'
- +'Quit'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0
- +#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0
- +#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#29'c'#155#22#25'`'
- +#152'9'#20']'#149'b'#16'Z'#146#136#13'X'#144#164#19'\'#146#252#12'W'#143#237
- +#153#153#153#255'qqq'#255'TTT'#255'QQQ'#255'OOO'#255'LLL'#255'JJJ'#255'GGG'
- +#255'EEE'#255'%g'#157#255'2t'#168#255'=|'#175#255'G'#132#181#255'N'#138#186
- +#255'>~'#173#255#12'W'#143#234#255#255#255#0#255#255#255#0'XXX'#255#162#162
- +#162#255#162#162#162#255#163#163#163#255#164#164#164#255#164#164#164#255#165
- +#165#165#255'/o'#165#255'x'#171#210#255'x'#171#211#255's'#167#209#255'i'#160
- +#205#255'@'#127#174#255#15'Y'#145#234#255#255#255#0#255#255#255#0'\\\'#255
- +#161#161#161#255''#255'4~;'#255'1y7'#255'.u4'#255'I'
- +#145'P'#255'F'#143'L'#255'9s='#255#161#161#161#255#162#162#162#255'E~'#180
- +#255#136#183#217#255'g'#163#207#255'a'#158#204#255'c'#159#204#255'E'#131#177
- +#255#31'd'#156#234';'#135'B'#255#137#203#146#255#132#200#141#255#128#198#136
- +#255'{'#195#131#255'w'#193#127#255'G'#143'M'#255';t?'#255#161#161#161#255'L'
- +#132#186#255#141#187#219#255'n'#168#209#255'f'#166#209#255'_'#180#223#255'G'
- +#133#177#255'%i'#161#234'>'#139'F'#255#143#206#153#255'}'#198#135#255'x'#195
- +#129#255's'#192'|'#255't'#192'|'#255'y'#194#129#255'I'#144'O'#255'T'#127'W'
- +#255'T'#137#191#255#148#191#221#255'u'#173#212#255'c'#184#225#255'K'#212#255
- +#255'B'#139#184#255',n'#166#234'A'#144'J'#255#148#210#159#255#145#208#154#255
- +#141#205#150#255#137#203#146#255#132#200#141#255'Q'#152'X'#255'A|F'#255#159
- +#159#159#255'Z'#142#196#255#152#195#224#255'|'#179#215#255't'#175#214#255'^'
- +#196#237#255'K'#136#179#255'4s'#171#234'D'#148'M'#255'B'#145'K'#255'?'#141'H'
- +#255'='#137'E'#255']'#164'e'#255'Z'#160'a'#255'E'#131'K'#255#158#158#158#255
- +#158#158#158#255'`'#146#201#255#158#199#226#255#131#184#218#255'}'#180#215
- +#255'~'#179#215#255'O'#137#180#255';y'#177#234#255#255#255#0#255#255#255#0'w'
- +'ww'#255#154#154#154#255'='#138'E'#255'I'#138'O'#255#156#156#156#255#157#157
- +#157#255#157#157#157#255'f'#150#204#255#162#203#227#255#137#189#220#255#131
- +#185#218#255#132#185#218#255'Q'#139#181#255'C~'#182#234#255#255#255#0#255#255
- +#255#0'zzz'#255#153#153#153#255'R'#145'Y'#255#153#154#153#255#155#155#155#255
- +#156#156#156#255#156#156#156#255'l'#154#208#255#167#206#229#255#143#193#223
- +#255#137#189#220#255#139#189#220#255'S'#141#182#255'K'#132#188#234#255#255
- +#255#0#255#255#255#0'}}}'#255#153#153#153#255#153#153#153#255#154#154#154#255
- +#154#154#154#255#155#155#155#255#155#155#155#255'o'#157#211#255#170#209#231
- +#255#171#209#231#255#152#199#225#255#145#194#222#255'V'#143#183#255'R'#137
- +#193#234#255#255#255#0#255#255#255#0#128#128#128#255'~~~'#255'|||'#255'zzz'
- +#255'www'#255'uuu'#255'rrr'#255'q'#158#212#255'o'#158#214#255#135#178#220#255
- +#171#211#232#255#169#208#230#255'X'#144#184#255'Y'#142#198#234#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'p'#158#214
- +#219'm'#156#212#255#133#177#218#255'Z'#145#185#255'`'#147#203#234#255#255#255
+ +#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#200#154
+ +'|'#255#199#152'y'#255#167'`1'#237#186'k7'#254#237#202#179#255#224#162'z'#255
+ +#254#250#247#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+ +'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255#253#249#246#255
+ +#202#141'e'#255#201#155'|'#255#167'`1'#254#187'l8'#255#238#204#182#255#225
+ +#162'z'#255#254#250#247#255#191#220#194#255#191#220#194#255#191#220#194#255
+ +#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194
+ +#255#253#249#246#255#205#144'h'#255#204#158#129#255#168'a2'#255#187'k8'#255
+ +#239#206#184#255#225#162'y'#255#254#250#247#255'b'#192#136#255'b'#192#136#255
+ +'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+ +'b'#192#136#255#253#249#246#255#207#147'j'#255#206#163#132#255#170'a2'#255
+ +#186'j6'#255#239#208#187#255#226#162'z'#255#254#251#248#255#254#251#248#255
+ +#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248
+ +#255#254#251#248#255#254#251#248#255#254#251#248#255#211#150'm'#255#210#167
+ +#138#255#171'b2'#255#187'j6'#255#240#210#190#255#226#163'z'#255#226#163'z'
+ +#255#225#163'z'#255#226#163'{'#255#225#163'{'#255#224#161'x'#255#222#159'w'
+ +#255#221#159'v'#255#220#157't'#255#217#155'r'#255#216#153'q'#255#214#153'p'
+ +#255#213#171#142#255#173'c3'#255#187'j6'#255#242#213#194#255#227#163'z'#255
+ +#227#163'z'#255#226#163'{'#255#226#163'{'#255#226#164'{'#255#225#162'y'#255
+ +#224#161'x'#255#222#160'w'#255#222#158'u'#255#220#157't'#255#218#155's'#255
+ +#217#155's'#255#218#176#149#255#175'd3'#255#187'j6'#255#242#216#197#255#227
+ +#164'{'#255#227#163'z'#255#227#164'z'#255#226#164'{'#255#226#163'{'#255#225
+ +#163'{'#255#225#162'y'#255#223#160'w'#255#222#159'v'#255#221#158't'#255#219
+ +#156'r'#255#220#157't'#255#221#181#154#255#177'e4'#255#187'k6'#255#244#217
+ +#199#255#230#166'}'#255#200#140'd'#255#201#141'e'#255#201#142'g'#255#203#146
+ +'l'#255#203#146'm'#255#202#144'i'#255#200#140'e'#255#200#140'd'#255#200#140
+ +'d'#255#200#140'd'#255#218#156't'#255#225#186#159#255#179'f4'#255#187'k6'#254
+ +#244#220#201#255#231#167'}'#255#249#236#225#255#249#236#225#255#249#237#227
+ +#255#252#244#238#255#253#250#247#255#253#247#243#255#250#237#229#255#247#231
+ +#219#255#247#229#217#255#246#229#216#255#222#160'w'#255#228#190#164#255#180
+ +'g4'#255#188'k6'#250#245#221#204#255#231#168'~'#255#250#240#232#255#250#240
+ +#232#255#201#141'f'#255#250#240#233#255#253#248#243#255#254#250#248#255#252
+ +#244#239#255#249#233#223#255#247#231#219#255#247#229#217#255#224#162'x'#255
+ +#231#194#169#255#182'h5'#255#188'k6'#240#246#223#208#255#232#168'~'#255#252
+ +#246#241#255#252#246#241#255#200#140'd'#255#250#241#233#255#251#244#238#255
+ +#253#250#247#255#253#249#246#255#250#240#232#255#248#232#221#255#247#230#219
+ +#255#225#163'z'#255#239#213#195#255#183'i5'#254#188'k6'#216#246#223#209#255
+ +#233#170#128#255#254#250#246#255#253#250#246#255#200#140'd'#255#251#243#238
+ +#255#251#241#234#255#252#246#242#255#254#251#248#255#252#246#241#255#249#236
+ +#226#255#248#231#219#255#238#208#186#255#236#208#189#255#187'p>'#248#188'k6'
+ +#155#246#224#209#255#247#224#209#255#254#251#248#255#254#251#247#255#253#249
+ +#246#255#252#245#240#255#250#240#234#255#251#242#237#255#253#249#246#255#253
+ +#250#247#255#251#241#235#255#248#233#223#254#236#208#189#251#201#137'^'#236
+ +#181'i5c'#188'k6q'#188'k6'#144#188'k6'#204#188'k6'#238#188'k6'#250#187'k6'
+ ,#254#187'k6'#255#187'j6'#255#187'j6'#255#188'l9'#255#189'n;'#255#187'm:'#255
+ +#187'k8'#239#187'p>'#203#182'i5T'#255#255#255#0#7'OnClick'#7#15'acSaveAsExec'
+ +'ute'#0#0#9'TMenuItem'#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#7'mnu'
+ +'Quit'#6'Action'#7#6'AcQuit'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0
+ +#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0
+ +#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#29'c'#155#22#25'`'#152'9'#20']'#149'b'#16'Z'#146#136#13'X'#144#164#19'\'#146
+ +#252#12'W'#143#237#153#153#153#255'qqq'#255'TTT'#255'QQQ'#255'OOO'#255'LLL'
+ +#255'JJJ'#255'GGG'#255'EEE'#255'%g'#157#255'2t'#168#255'=|'#175#255'G'#132
+ +#181#255'N'#138#186#255'>~'#173#255#12'W'#143#234#255#255#255#0#255#255#255#0
+ +'XXX'#255#162#162#162#255#162#162#162#255#163#163#163#255#164#164#164#255#164
+ +#164#164#255#165#165#165#255'/o'#165#255'x'#171#210#255'x'#171#211#255's'#167
+ +#209#255'i'#160#205#255'@'#127#174#255#15'Y'#145#234#255#255#255#0#255#255
+ +#255#0'\\\'#255#161#161#161#255''#255'4~;'#255'1y7'
+ +#255'.u4'#255'I'#145'P'#255'F'#143'L'#255'9s='#255#161#161#161#255#162#162
+ +#162#255'E~'#180#255#136#183#217#255'g'#163#207#255'a'#158#204#255'c'#159#204
+ +#255'E'#131#177#255#31'd'#156#234';'#135'B'#255#137#203#146#255#132#200#141
+ +#255#128#198#136#255'{'#195#131#255'w'#193#127#255'G'#143'M'#255';t?'#255#161
+ +#161#161#255'L'#132#186#255#141#187#219#255'n'#168#209#255'f'#166#209#255'_'
+ +#180#223#255'G'#133#177#255'%i'#161#234'>'#139'F'#255#143#206#153#255'}'#198
+ +#135#255'x'#195#129#255's'#192'|'#255't'#192'|'#255'y'#194#129#255'I'#144'O'
+ +#255'T'#127'W'#255'T'#137#191#255#148#191#221#255'u'#173#212#255'c'#184#225
+ +#255'K'#212#255#255'B'#139#184#255',n'#166#234'A'#144'J'#255#148#210#159#255
+ +#145#208#154#255#141#205#150#255#137#203#146#255#132#200#141#255'Q'#152'X'
+ +#255'A|F'#255#159#159#159#255'Z'#142#196#255#152#195#224#255'|'#179#215#255
+ +'t'#175#214#255'^'#196#237#255'K'#136#179#255'4s'#171#234'D'#148'M'#255'B'
+ +#145'K'#255'?'#141'H'#255'='#137'E'#255']'#164'e'#255'Z'#160'a'#255'E'#131'K'
+ +#255#158#158#158#255#158#158#158#255'`'#146#201#255#158#199#226#255#131#184
+ +#218#255'}'#180#215#255'~'#179#215#255'O'#137#180#255';y'#177#234#255#255#255
+ +#0#255#255#255#0'www'#255#154#154#154#255'='#138'E'#255'I'#138'O'#255#156#156
+ +#156#255#157#157#157#255#157#157#157#255'f'#150#204#255#162#203#227#255#137
+ +#189#220#255#131#185#218#255#132#185#218#255'Q'#139#181#255'C~'#182#234#255
+ +#255#255#0#255#255#255#0'zzz'#255#153#153#153#255'R'#145'Y'#255#153#154#153
+ +#255#155#155#155#255#156#156#156#255#156#156#156#255'l'#154#208#255#167#206
+ +#229#255#143#193#223#255#137#189#220#255#139#189#220#255'S'#141#182#255'K'
+ +#132#188#234#255#255#255#0#255#255#255#0'}}}'#255#153#153#153#255#153#153#153
+ +#255#154#154#154#255#154#154#154#255#155#155#155#255#155#155#155#255'o'#157
+ +#211#255#170#209#231#255#171#209#231#255#152#199#225#255#145#194#222#255'V'
+ +#143#183#255'R'#137#193#234#255#255#255#0#255#255#255#0#128#128#128#255'~~~'
+ +#255'|||'#255'zzz'#255'www'#255'uuu'#255'rrr'#255'q'#158#212#255'o'#158#214
+ +#255#135#178#220#255#171#211#232#255#169#208#230#255'X'#144#184#255'Y'#142
+ +#198#234#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0'm'#156#212#137'j'#154#210#251'f'#151#207#238#7'OnClick'
- +#7#13'acQuitExecute'#0#0#0#9'TMenuItem'#7'mnuEdit'#7'Caption'#6#4'Edit'#0#9
- +'TMenuItem'#9'MenuItem2'#6'Action'#7#6'AcEdit'#9'AutoCheck'#9#11'Bitmap.Data'
- +#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0
- +#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#255#0'p'#158#214#219'm'#156#212#255#133#177#218#255'Z'#145#185#255'`'
+ +#147#203#234#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#19'@X'
- +#255#21'B^'#255'%i'#156#255',v'#180#255';'#139#186#173#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#18'BY'#255']'#156
- +#212#255#166#207#245#255#169#207#236#255'H'#139#193#255',v'#180#255#255#255
- ,#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#30'm'#147#255#203
- +#227#249#255'a'#170#236#255'@'#152#232#255#21'g'#194#255#22'`'#170#255',v'
- +#180#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
- +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#30'm'#147#255#200
- +#225#242#255#209#231#250#255'4}'#181#255'1'#153#195#255'm'#196#220#255'J'#156
- +#207#255'4'#131#199#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
- +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0' c'#152' &'#137
- +#185#255#176#203#225#255'g'#169#200#255'`'#220#245#255'D'#214#244#255#142#238
- +#250#255']'#180#230#255';'#143#217#255#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0'&'#137#185#255#190#230#242#255#179#244#252#255'`'#220#245#255
- +'D'#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0'm'#156#212#137'j'#154#210#251'f'
+ +#151#207#238#7'OnClick'#7#13'acQuitExecute'#0#0#0#9'TMenuItem'#7'mnuEdit'#7
+ +'Caption'#6#4'Edit'#0#9'TMenuItem'#9'MenuItem2'#6'Action'#7#6'AcEdit'#9'Auto'
+ +'Check'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('
+ +#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0
+ +#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0''''#144#191#255#195#237#248#255#179
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#19'@X'#255#21'B^'#255'%i'#156#255',v'#180#255';'#139#186
+ +#173#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#18'BY'#255']'#156#212#255#166#207#245#255#169#207#236#255'H'#139
+ ,#193#255',v'#180#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#30'm'#147#255#203#227#249#255'a'#170#236#255'@'#152#232#255#21'g'
+ +#194#255#22'`'#170#255',v'#180#255#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#30'm'#147#255#200#225#242#255#209#231#250#255'4}'#181#255'1'#153
+ +#195#255'm'#196#220#255'J'#156#207#255'4'#131#199#255#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0' c'#152' &'#137#185#255#176#203#225#255'g'#169#200#255'`'#220
+ +#245#255'D'#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0'&'#137#185#255#190#230#242#255#179
+#244#252#255'`'#220#245#255'D'#214#244#255#142#238#250#255']'#180#230#255';'
+#143#217#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255
- +#195#237#248#255#179#244#252#255'`'#220#245#255'D'#214#244#255#142#238#250
- +#255']'#180#230#255';'#143#217#255#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0'/'#186#228#255#195#237#248#255#179#244#252#255'`'#220#245#255'D'
- +#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195#237#248#255#179#244#252
- +#255'h'#217#245#255'o'#207#243#255'Y'#157#208#255's'#171#221#255'O'#145#201
- +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195
- +#237#248#255#168#226#248#255'l'#174#221#255#165#207#244#255#165#207#244#255
- +#189#219#247#255'S'#147#203#247#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0'/'#186#228#255#167#212#244#255#197#225#248#255#204#227#249#255#204#227
- +#249#255#189#219#247#255'O'#144#201#253#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0''''#144#191
+ +#255#195#237#248#255#179#244#252#255'`'#220#245#255'D'#214#244#255#142#238
+ +#250#255']'#180#230#255';'#143#217#255#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0'P'#168#217#255'j'#165#216#255#201#225#247#255
- +#203#227#248#255'B'#149#202#255'1'#130#194#174#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#9'O'#170#219#234'P'#147#202
- +#253'N'#144#200#255'/'#157#210#223'5'#164#222#25#255#255#255#0#255#255#255#0
+ +#255#255#255#0'/'#186#228#255#195#237#248#255#179#244#252#255'`'#220#245#255
+ +'D'#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195#237#248#255#179#244
+ +#252#255'`'#220#245#255'D'#214#244#255#142#238#250#255']'#180#230#255';'#143
+ +#217#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195
+ +#237#248#255#179#244#252#255'h'#217#245#255'o'#207#243#255'Y'#157#208#255's'
+ +#171#221#255'O'#145#201#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +'/'#186#228#255#195#237#248#255#168#226#248#255'l'#174#221#255#165#207#244
+ +#255#165#207#244#255#189#219#247#255'S'#147#203#247#255#255#255#0#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0'/'#186#228#255#167#212#244#255#197#225#248#255#204
+ +#227#249#255#204#227#249#255#189#219#247#255'O'#144#201#253#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'TMenuItem'#9'mnuFor'
- +'mat'#7'Caption'#6#6'Format'#0#9'TMenuItem'#7'MnuFOnt'#6'Action'#7#6'AcFont'
- +#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16
- +#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0'P'#168#217#255'j'#165#216
+ +#255#201#225#247#255#203#227#248#255'B'#149#202#255'1'#130#194#174#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#9'O'#170
+ +#219#234'P'#147#202#253'N'#144#200#255'/'#157#210#223'5'#164#222#25#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'T'
+ +'MenuItem'#9'mnuFormat'#7'Caption'#6#6'Format'#0#9'TMenuItem'#7'MnuFOnt'#6'A'
+ +'ction'#7#6'AcFont'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0
+ +'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0
+ +#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
@@ -310,110 +311,156 @@ LazarusResources.Add('TForm1','FORMDATA',[
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#206'h8'#174#218#143']'#254#219#144'`'#255
+ +#215#131'P'#237#196'P+'#141#189'B#'#16#188'?"*'#195'M+'#162#208'qB'#234#214
+ +'~Q'#255#213'|M'#255#198'U1'#189#182'9'#29'1'#255#255#255#0#255#255#255#0#255
+ +#255#255#0#202'\/'#10#203'_0D'#225#164'u'#255#218#140'X'#236#198'R,='#255#255
+ +#255#0#255#255#255#0#191'E$'#19#195'H'''#127#220#150'k'#255#219#143'`'#255
+ +#189'?!T'#182'8'#30#2#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#203']0'#1#211't?'#155#226#169'|'#255#204'f7'#153#255#255#255#0#255#255#255#0
+ +#255#255#255#0#204'c7'#177#223#160'w'#255#218#137'Z'#255#187'>""'#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#204
+ +'c2'#21#219#147'^'#234#226#167'y'#255#216#131'J'#211#207'j:'#178#206'h9'#181
+ ,#213'zE'#216#227#168#129#255#217#134'V'#249#190'A#'#27#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#206'h8'#174#218#143']'#254#219#144'`'#255#215#131'P'#237#196
- +'P+'#141#189'B#'#16#188'?"*'#195'M+'#162#208'qB'#234#214'~Q'#255#213'|M'#255
- +#198'U1'#189#182'9'#29'1'#255#255#255#0#255#255#255#0#255#255#255#0#202'\/'
- +#10#203'_0D'#225#164'u'#255#218#140'X'#236#198'R,='#255#255#255#0#255#255#255
- +#0#191'E$'#19#195'H'''#127#220#150'k'#255#219#143'`'#255#189'?!T'#182'8'#30#2
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#203']0'#1#211't?'
- +#155#226#169'|'#255#204'f7'#153#255#255#255#0#255#255#255#0#255#255#255#0#204
- +'c7'#177#223#160'w'#255#218#137'Z'#255#187'>""'#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#204'c2'#21#219#147
- +'^'#234#226#167'y'#255#216#131'J'#211#207'j:'#178#206'h9'#181#213'zE'#216#227
- ,#168#129#255#217#134'V'#249#190'A#'#27#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#207'j6\'#223
- +#157'h'#246#218#139'R'#209#203'_1N'#199'Y.*'#205'g7'#160#225#166'z'#255#216
- +#134'S'#242#191'F%'#13#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
- +#0#255#255#255#0#255#255#255#0#255#255#255#0#208'j5'#3#215#128'B'#170#223#159
- +'j'#247#205'f4f'#201']/'#10#204'a3'#136#225#166'y'#255#213'zD'#210#194'J'''#6
+ +#207'j6\'#223#157'h'#246#218#139'R'#209#203'_1N'#199'Y.*'#205'g7'#160#225#166
+ +'z'#255#216#134'S'#242#191'F%'#13#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#208'j5'#3#215#128'B'
+ +#170#223#159'j'#247#205'f4f'#201']/'#10#204'a3'#136#225#166'y'#255#213'zD'
+ +#210#194'J'''#6#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#209'q8"'#222#155'c'#226
+ +#220#150'^'#223#207'i5T'#207'i5'#128#226#169'|'#255#209'l:'#165#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#209'q8"'#222#155'c'#226#220#150'^'#223
- +#207'i5T'#207'i5'#128#226#169'|'#255#209'l:'#165#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#212'y'#152#203'_0'#8#255#255#255#0#255#255#255#0#255
+ +#255#255#255#0#255#255#255#0#255#255#255#0#214'};'#28#221#150'V'#186#227#169
+ +'s'#242#225#168's'#245#225#164'q'#247#211'w>'#152#203'_0'#8#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#215#131'>S'#226#167'l'#222#233#188#145#255#231#186#143
- +#255#231#183#139#255#226#164'q'#251#214'~B'#182#203'\/'#10#255#255#255#0#255
+ +#255#0#255#255#255#0#255#255#255#0#215#131'>S'#226#167'l'#222#233#188#145#255
+ +#231#186#143#255#231#183#139#255#226#164'q'#251#214'~B'#182#203'\/'#10#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#216#135'@@'#216#139'C'#133#218#142'I'#148#217#137'C'#143
- +#216#132'@'#144#216#132'A'#154#211's:'#138#204'b2'#13#201'[.'#1#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#0#255#255#255#0#255#255#255#0#216#135'@@'#216#139'C'#133#218#142'I'#148
+ +#217#137'C'#143#216#132'@'#144#216#132'A'#154#211's:'#138#204'b2'#13#201'[.'
+ +#1#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#0#0#9'TMenuItem'#15'MnuTextRotation'#7'Caption'#6#13'Text rotation'#0#9'TMe'
- +'nuItem'#10'MenuItem29'#6'Action'#7#11'AcTextHoriz'#9'AutoCheck'#9#0#0#9'TMe'
- +'nuItem'#10'MenuItem30'#6'Action'#7#12'AcTextVertCW'#9'AutoCheck'#9#0#0#9'TM'
- +'enuItem'#10'MenuItem31'#6'Action'#7#13'AcTextVertCCW'#9'AutoCheck'#9#0#0#9
- +'TMenuItem'#10'MenuItem32'#6'Action'#7#13'AcTextStacked'#9'AutoCheck'#9#0#0#0
- +#9'TMenuItem'#15'MnuHorAlignment'#7'Caption'#6#20'Horizontal alignment'#0#9
- +'TMenuItem'#13'MnuHorDefault'#6'Action'#7#17'AcHorDefaultAlign'#9'AutoCheck'
- +#9#0#0#9'TMenuItem'#9'MenuItem6'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#9'MenuIt'
- +'em3'#6'Action'#7#11'AcLeftAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0
- +'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0
- +#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#255#0#0#0#9'TMenuItem'#15'MnuTextRotation'#7'Caption'#6#13'Text rot'
+ +'ation'#0#9'TMenuItem'#10'MenuItem29'#6'Action'#7#11'AcTextHoriz'#9'AutoChec'
+ +'k'#9#0#0#9'TMenuItem'#10'MenuItem30'#6'Action'#7#12'AcTextVertCW'#9'AutoChe'
+ +'ck'#9#0#0#9'TMenuItem'#10'MenuItem31'#6'Action'#7#13'AcTextVertCCW'#9'AutoC'
+ +'heck'#9#0#0#9'TMenuItem'#10'MenuItem32'#6'Action'#7#13'AcTextStacked'#9'Aut'
+ +'oCheck'#9#0#0#0#9'TMenuItem'#15'MnuHorAlignment'#7'Caption'#6#20'Horizontal'
+ +' alignment'#0#9'TMenuItem'#13'MnuHorDefault'#6'Action'#7#17'AcHorDefaultAli'
+ +'gn'#9'AutoCheck'#9#0#0#9'TMenuItem'#9'MenuItem6'#7'Caption'#6#1'-'#0#0#9'TM'
+ +'enuItem'#9'MenuItem3'#6'Action'#7#11'AcLeftAlign'#9'AutoCheck'#9#11'Bitmap.'
+ +'Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16
+ +#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +'<<<'#255'555'#255'///'#255')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20#20
- +#20#255#15#15#15#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#255#0'<<<'#255'555'#255'///'#255')))'#255'$$$'#255#30#30#30#255#25
+ +#25#25#255#20#20#20#255#15#15#15#255#255#255#255#0#255#255#255#0#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>>>'#255'888'
- +#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22#255#17#17#17
- +#255#12#12#12#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'XXX'
- +#255'RRR'#255'LLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'...'#255'((('#255
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>'
+ +'>>'#255'888'#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22
+ +#255#17#17#17#255#12#12#12#255#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'III'
- +#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#255
+ +#255#255#0'XXX'#255'RRR'#255'LLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'..'
+ +'.'#255'((('#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'O'
+ +'OO'#255'III'#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
,#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0'ooo'#255'kkk'#255'fff'#255'aaa'#255'\'
- +'\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'ooo'#255'kkk'#255'fff'
+ +#255'aaa'#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255
- +'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'
- +#255'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0'vvv'#255'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'
+ +#255'SSS'#255'NNN'#255'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#9'TMe'
+ +'nuItem'#9'MenuItem4'#6'Action'#7#16'AcHorCenterAlign'#9'AutoCheck'#9#11'Bit'
+ +'map.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0
+ +#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0'555k///'#255')))'#255'$$$'#255#30#30#30
+ +#255#25#25#25#255#20#20#20#255#15#15#15#255#11#11#11#255#7#7#7'k'#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>'
+ +'>>'#255'888'#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22
+ +#255#17#17#17#255#12#12#12#255#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0'RRRkLLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'..'
+ +'.'#255'((('#255'###'#255#29#29#29'k'#255#255#255#0#255#255#255#0#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'II'
+ +'I'#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'kkkkfff'#255'aaa'
+ +#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'999k'#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255'ttt'#255'p'
+ +'pp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'#255'HHH'
+ +#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ ,#255#255#0#255#255#255#0#255#255#255#0#0#0#9'TMenuItem'#9'MenuItem5'#6'Actio'
+ +'n'#7#12'AcRightAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'B'
+ +'M6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0
+ +#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#9'TMenuItem'#9'MenuItem'
- +'4'#6'Action'#7#16'AcHorCenterAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0
- +#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0
- +#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0'555k///'#255')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20#20
- +#20#255#15#15#15#255#11#11#11#255#7#7#7'k'#255#255#255#0#255#255#255#0#255
+ +#255#255#255#0#255#255#255#0')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20
+ +#20#20#255#15#15#15#255#11#11#11#255#7#7#7#255#3#3#3#255#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
@@ -423,95 +470,48 @@ LazarusResources.Add('TForm1','FORMDATA',[
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0'RRRkLLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'...'#255'((('#255'##'
- +'#'#255#29#29#29'k'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#0#255#255#255#0#255#255#255#0'FFF'#255'@@@'#255':::'#255'444'#255'...'
+ +#255'((('#255'###'#255#29#29#29#255#24#24#24#255#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'III'#255'CCC'#255
- +'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0'kkkkfff'#255'aaa'#255'\\\'#255'WWW'
- +#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'999k'#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'II'
+ +'I'#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255'ttt'#255'ppp'#255'lll'
- +#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'#255'HHH'#255'BBB'#255
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0'aaa'#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'99'
+ +'9'#255'333'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'
+ +#255'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255
+ +'NNN'#255'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+ +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- ,#255#255#255#0#255#255#255#0#0#0#9'TMenuItem'#9'MenuItem5'#6'Action'#7#12'Ac'
- +'RightAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0
- +#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0
- +'d'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20#20#20#255
- +#15#15#15#255#11#11#11#255#7#7#7#255#3#3#3#255#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>>>'#255'888'#255'222'#255',,'
- +','#255'&&&'#255' '#255#27#27#27#255#22#22#22#255#17#17#17#255#12#12#12#255
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0'FFF'#255'@@@'#255':::'#255'444'#255'...'#255'((('
- +#255'###'#255#29#29#29#255#24#24#24#255#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'III'#255'C'
- +'CC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +'aaa'#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'999'#255'333'
- +#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255'ttt'
- +#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'#255
- +'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'TMenuItem'#16'M'
+ +'nuVertAlignment'#7'Caption'#6#18'Vertical alignment'#0#9'TMenuItem'#14'MnuV'
+ +'ertDefault'#6'Action'#7#15'AcVAlignDefault'#9'AutoCheck'#9#0#0#9'TMenuItem'
+ +#9'MenuItem7'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#10'MnuVertTop'#6'Action'#7
+ +#11'AcVAlignTop'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0
+ +#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0
+ +#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'TMenuItem'#16'MnuVe'
- +'rtAlignment'#7'Caption'#6#18'Vertical alignment'#0#9'TMenuItem'#14'MnuVertD'
- +'efault'#6'Action'#7#15'AcVAlignDefault'#9'AutoCheck'#9#0#0#9'TMenuItem'#9'M'
- +'enuItem7'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#10'MnuVertTop'#6'Action'#7#11
- +'AcVAlignTop'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0
- +#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0
- +#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
- +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
- +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0';;;'#0'444'#0'...'#0'(('
- +'('#0'###'#0#29#29#29#0#24#24#24#0#19#19#19#0#15#15#15#0#11#11#11#0#7#7#7#0#3
- +#3#3#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
- +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+ +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0';;;'#0'444'#0'...'#0
+ +'((('#0'###'#0#29#29#29#0#24#24#24#0#19#19#19#0#15#15#15#0#11#11#11#0#7#7#7#0
+ +#3#3#3#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+ +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
,#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'III'#0'CCC'#0
+'==='#0'777'#0'111'#0'+++'#0'%%%'#0#31#31#31#0#26#26#26#0#21#21#21#0#17#17#17
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 8dd1a66f5..5684e9eb7 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -137,10 +137,11 @@ type
TsUsedFormattingFields = set of TsUsedFormattingField;
{@@ Number/cell formatting. Only uses a subset of the default formats,
- enough to be able to read/write date values. }
+ enough to be able to read/write date/time values.
+ nfCustom allows to apply a format string directly. }
TsNumberFormat = (nfGeneral, nfFixed, nfFixedTh, nfExp, nfSci, nfPercentage,
- nfShortDateTime, nfFmtDateTime, nfShortDate, nfShortTime, nfLongTime,
- nfShortTimeAM, nfLongTimeAM, nfTimeInterval);
+ nfShortDateTime, nfFmtDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
+ nfShortTimeAM, nfLongTimeAM, nfTimeInterval, nfCustom);
{@@ Text rotation formatting. The text is rotated relative to the standard
orientation, which is from left to right horizontal:
@@ -364,14 +365,17 @@ type
{ Writing of values }
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
- AFormat: TsNumberFormat = nfGeneral; ADecimals: Word = 2);
+ AFormat: TsNumberFormat = nfGeneral; ADecimals: Word = 2); overload;
+ procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
+ AFormatString: String); overload;
procedure WriteBlank(ARow, ACol: Cardinal);
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
{ Writing of cell attributes }
- procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat);
+ procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
+ const AFormatString: String);
function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
@@ -481,6 +485,50 @@ type
property FileFormat: TsSpreadsheetFormat read FFormat;
end;
+
+ {@@ Contents of the format record }
+
+ TsNumFormatData = class
+ public
+ Index: Integer;
+ NumFormat: TsNumberFormat;
+ Decimals: Integer;
+ FormatString: string;
+ end;
+
+ {@@ Specialized list for number format items }
+
+ TsCustomNumFormatList = class(TFPList)
+ private
+ function GetItem(AIndex: Integer): TsNumFormatData;
+ procedure SetItem(AIndex: Integer; AValue: TsNumFormatData);
+ protected
+ FFirstFormatIndexInFile: Integer;
+ FNextFormatIndex: Integer;
+ procedure AddBuiltinFormats; virtual;
+ procedure Analyze(var AFormatString: String; var ANumFormat: TsNumberFormat;
+ var ADecimals: Word); virtual;
+ procedure RemoveFormat(AIndex: Integer);
+ public
+ constructor Create;
+ destructor Destroy; override;
+ function AddFormat(AFormatCell: PCell): Integer; overload;
+ function AddFormat(AFormatIndex: Integer; ANumFormat: TsNumberFormat;
+ AFormatString: String = ''; ADecimals: Integer = 0): Integer; overload;
+ procedure AnalyzeAndAdd(AFormatIndex: Integer; AFormatString: String);
+ procedure Clear;
+ procedure Delete(AIndex: Integer);
+ function Find(AFormatCell: PCell): integer; overload;
+ function Find(ANumFormat: TsNumberFormat; AFormatString: String;
+ ADecimals: Integer): Integer; overload;
+ function Find(AFormatIndex: Integer): Integer; overload;
+ function FormatStringForWriting(AIndex: Integer): String; virtual;
+ procedure Sort;
+
+ property FirstFormatIndexInFile: Integer read FFirstFormatIndexInFile;
+ property Items[AIndex: Integer]: TsNumFormatData read GetItem write SetItem; default;
+ end;
+
{@@ TsSpreadReader class reference type }
TsSpreadReaderClass = class of TsCustomSpreadReader;
@@ -491,6 +539,8 @@ type
protected
FWorkbook: TsWorkbook;
FWorksheet: TsWorksheet;
+ FNumFormatList: TsCustomNumFormatList;
+ procedure CreateNumFormatList; virtual; abstract;
{ Record reading methods }
procedure ReadBlank(AStream: TStream); virtual; abstract;
procedure ReadFormula(AStream: TStream); virtual; abstract;
@@ -498,11 +548,13 @@ type
procedure ReadNumber(AStream: TStream); virtual; abstract;
public
constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
+ destructor Destroy; override;
{ General writing methods }
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); virtual;
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); virtual;
procedure ReadFromStrings(AStrings: TStrings; AData: TsWorkbook); virtual;
property Workbook: TsWorkbook read FWorkbook;
+ property NumFormatList: TsCustomNumFormatList read FNumFormatList;
end;
{@@ TsSpreadWriter class reference type }
@@ -517,12 +569,17 @@ type
private
FWorkbook: TsWorkbook;
protected
+ FNumFormatList: TsCustomNumFormatList;
{ Helper routines }
procedure AddDefaultFormats(); virtual;
+ procedure CreateNumFormatList; virtual; abstract;
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
function FindFormattingInList(AFormat: PCell): Integer;
+ procedure FixFormat(ACell: PCell); virtual;
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
procedure ListAllFormattingStyles;
+ procedure ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
+ procedure ListAllNumFormats; virtual;
{ Helpers for writing }
procedure WriteCellCallback(ACell: PCell; AStream: TStream);
procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
@@ -541,12 +598,14 @@ type
FFormattingStyles: array of TCell;
NextXFIndex: Integer; // Indicates which should be the next XF (Style) Index when filling the styles list
constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
+ destructor Destroy; override;
{ General writing methods }
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual;
procedure WriteToStream(AStream: TStream); virtual;
procedure WriteToStrings(AStrings: TStrings); virtual;
property Workbook: TsWorkbook read FWorkbook;
+ property NumFormatList: TsCustomNumFormatList read FNumFormatList;
end;
{@@ List of registered formats }
@@ -615,10 +674,6 @@ procedure RegisterSpreadFormat(
AFormat: TsSpreadsheetFormat);
function GetFileFormatName(AFormat: TsSpreadsheetFormat): String;
-
-function SciFloat(AValue: Double; ADecimals: Word): String;
-function TimeIntervalToString(AValue: TDateTime): String;
-
procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
implementation
@@ -731,50 +786,6 @@ begin
end;
-{@@
- Formats the number AValue in "scientific" format with the given number of
- decimals. "Scientific" is the same as "exponential", but with exponents rounded
- to multiples of 3.
-}
-function SciFloat(AValue: Double; ADecimals: Word): String;
-var
- m: Double;
- ex: Integer;
-begin
- if AValue = 0 then
- Result := '0.0'
- else begin
- ex := floor(log10(abs(AValue))); // exponent
- // round exponent to multiples of 3
- ex := (ex div 3) * 3;
- if ex < 0 then dec(ex, 3);
- m := AValue * Power(10, -ex); // mantisse
- Result := Format('%.*fE%d', [ADecimals, m, ex]);
- end;
-end;
-
-{@@
- Formats the number AValue as a time string with hours, minutes and seconds.
- Unlike TimeToStr there can be more than 24 hours.
-}
-function TimeIntervalToString(AValue: TDateTime): String;
-var
- hrs: Integer;
- diff: Double;
- h,m,s,z: Word;
- ts: String;
-begin
- ts := DefaultFormatSettings.TimeSeparator;
- DecodeTime(frac(abs(AValue)), h, m, s, z);
- hrs := h + trunc(abs(AValue))*24;
- if z > 499 then inc(s);
- if hrs > 0 then
- Result := Format('%d%s%.2d%s%.2d', [hrs, ts, m, ts, s])
- else
- Result := Format('%d%s%.2d', [m, ts, s]);
- if AValue < 0.0 then Result := '-' + Result;
-end;
-
{@@
If a palette is coded as big-endian (e.g. by copying the rgb values from
the OpenOffice doc) the palette values can be converted by means of this
@@ -1109,31 +1120,33 @@ end;
function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
function FloatToStrNoNaN(const Value: Double;
- ANumberFormat: TsNumberFormat; ANumberFormatStr: ansistring): ansistring;
+ ANumberFormat: TsNumberFormat; ANumberFormatStr: string; ADecimals: Word): ansistring;
begin
if IsNan(Value) then
Result := ''
else
if ANumberFormat = nfSci then
- Result := SciFloat(Value, 1)
+ Result := SciFloat(Value, ADecimals)
else
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
Result := FloatToStr(Value)
else
if (ANumberFormat = nfPercentage) then
- Result := FormatFloat(ANumberFormatStr, Value*100) + '%'
+ Result := FormatFloat(ANumberFormatStr, Value*100) // '%' is already added to FormatStr.
else
Result := FormatFloat(ANumberFormatStr, Value);
end;
function DateTimeToStrNoNaN(const Value: Double;
- ANumberFormat: TsNumberFormat; ANumberFormatStr: String): ansistring;
+ ANumberFormat: TsNumberFormat; ANumberFormatStr: String; ADecimals: Word): ansistring;
begin
Result := '';
if not IsNaN(Value) then begin
+ (*
if ANumberFormat = nfTimeInterval then
- Result := TimeIntervalToString(Value)
+ Result := TimeIntervalToString(Value, ANumberFormatStr)
else
+ *)
if ANumberFormatStr = '' then
Result := FormatDateTime('c', Value)
else
@@ -1152,14 +1165,17 @@ begin
Exit;
end;
- case ACell^.ContentType of
- //cctFormula
- cctNumber: Result := FloatToStrNoNaN(ACell^.NumberValue, ACell^.NumberFormat, ACell^.NumberFormatStr);
- cctUTF8String: Result := ACell^.UTF8StringValue;
- cctDateTime: Result := DateTimeToStrNoNaN(ACell^.DateTimeValue, ACell^.NumberFormat, ACell^.NumberFormatStr);
- else
- Result := '';
- end;
+ with ACell^ do
+ case ContentType of
+ cctNumber:
+ Result := FloatToStrNoNaN(NumberValue, NumberFormat, NumberFormatStr, NumberDecimals);
+ cctUTF8String:
+ Result := UTF8StringValue;
+ cctDateTime:
+ Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr, NumberDecimals);
+ else
+ Result := '';
+ end;
end;
function TsWorksheet.ReadAsNumber(ARow, ACol: Cardinal): Double;
@@ -1322,14 +1338,33 @@ begin
nfExp:
ACell^.NumberFormatStr := '0' + decs + 'E+00';
nfSci:
- ACell^.NumberFormatStr := '';
+ ACell^.NumberFormatStr := '##0' + decs + 'E+0';
nfPercentage:
- ACell^.NumberFormatStr := '0' + decs;
+ ACell^.NumberFormatStr := '0' + decs + '%';
end;
end;
ChangedCell(ARow, ACol);
end;
+{@@
+ Writes a floating point number to the cell and uses a custom number format
+ specified by the format string.
+ NOTE that fpspreadsheet may not be able to detect the formatting when reading
+ the file. }
+procedure TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: Double;
+ AFormatString: String);
+var
+ ACell: PCell;
+begin
+ ACell := GetCell(ARow, ACol);
+ Include(ACell^.UsedFormattingFields, uffNumberFormat);
+ ACell^.ContentType := cctNumber;
+ ACell^.NumberValue := ANumber;
+ ACell^.NumberFormat := nfCustom;
+ ACell^.NumberFormatStr := AFormatString;
+ ChangedCell(ARow, ACol);
+end;
+
{@@
Writes as empty cell
@@ -1385,6 +1420,8 @@ begin
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat;
nfShortDate:
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat;
+ nfLongDate:
+ ACell^.NumberFormatStr := 'dd/mmm/yyyy';
nfShortTime:
ACell^.NumberFormatStr := 't';
nfLongTime:
@@ -1397,13 +1434,14 @@ begin
begin
fmt := lowercase(AFormatStr);
if fmt = 'dm' then ACell^.NumberFormatStr := 'd/mmm'
- else if fmt = 'my' then ACell^.NumberFormatSTr := 'mmm/yy'
- else if fmt = 'ms' then ACell^.NumberFormatStr := 'nn:ss'
- else if fmt = 'msz' then ACell^.NumberFormatStr := 'nn:ss.z'
+ else if fmt = 'my' then ACell^.NumberFormatStr := 'mmm/yy'
+ else if fmt = 'ms' then ACell^.NumberFormatStr := 'mm:ss' // Excel does not like the "n"
+ else if fmt = 'msz' then ACell^.NumberFormatStr := 'mm:ss.z'
else ACell^.NumberFormatStr := AFormatStr;
end;
nfTimeInterval:
- ACell^.NumberFormatStr := '';
+ if AFormatStr = '' then ACell^.NumberFormatStr := '[h]:mm:ss'
+ else ACell^.NumberFormatStr := AFormatStr;
end;
ChangedCell(ARow, ACol);
end;
@@ -1431,17 +1469,19 @@ end;
@param ARow The row of the cell
@param ACol The column of the cell
@param TsNumberFormat What format to apply
+ @param string Formatstring
@see TsNumberFormat
}
procedure TsWorksheet.WriteNumberFormat(ARow, ACol: Cardinal;
- ANumberFormat: TsNumberFormat);
+ ANumberFormat: TsNumberFormat; const AFormatString: String);
var
ACell: PCell;
begin
ACell := GetCell(ARow, ACol);
Include(ACell^.UsedFormattingFields, uffNumberFormat);
ACell^.NumberFormat := ANumberFormat;
+ ACell^.NumberFormatStr := AFormatString;
ChangedCell(ARow, ACol);
end;
@@ -2408,12 +2448,310 @@ begin
{$ENDIF}
end;
+
+{ TsCustomNumFormatList }
+
+constructor TsCustomNumFormatList.Create;
+begin
+ inherited Create;
+ AddBuiltinFormats;
+end;
+
+destructor TsCustomNumFormatList.Destroy;
+begin
+ Clear;
+ inherited Destroy;
+end;
+
+{ Adds a new number format data to the list and returns the list index of the
+ new (or present) item. }
+function TsCustomNumFormatList.AddFormat(AFormatIndex: Integer; ANumFormat: TsNumberFormat;
+ AFormatString: String = ''; ADecimals: Integer = 0): integer;
+var
+ item: TsNumFormatData;
+begin
+ item := TsNumFormatData.Create;
+ item.Index := AFormatIndex;
+ item.NumFormat := ANumFormat;
+ item.FormatString := AFormatString;
+ item.Decimals := ADecimals;
+ Result := inherited Add(item);
+end;
+
+function TsCustomNumFormatList.AddFormat(AFormatCell: PCell): Integer;
+var
+ item: TsNumFormatData;
+begin
+ if AFormatCell = nil then
+ raise Exception.Create('TsCustomNumFormat.Add: No nil pointers please');
+
+ if Count = 0 then
+ raise Exception.Create('TsCustomNumFormatList: Error in program logics: You must provide built-in formats first.');
+
+ Result := AddFormat(FNextFormatIndex, AFormatCell^.NumberFormat,
+ AFormatCell^.NumberFormatStr, AFormatCell^.NumberDecimals);
+
+ inc(FNextFormatIndex);
+end;
+
+{ Adds the builtin format items to the list. Must be called before user items
+ are added. Must specify FFirstFormatIndexInFile (BIFF5-8, e.g. don't save
+ formats <164) and must initialize the index of the first user format
+ (FNextFormatIndex) which is automatically incremented when adding user formats. }
+procedure TsCustomNumFormatList.AddBuiltinFormats;
+begin
+ // must be overridden
+end;
+
+{ Takes the format string (AFormatString) as it is read from the file and
+ extracts the number format type (ANumFormat) and the number of decimals
+ (ADecimals) out of it. If the format string cannot be directly handled by
+ fpc it has to be transformed to make it compatible. Can be done in
+ overridden versions which know more about the structure of the string in
+ the actual file format. }
+procedure TsCustomNumFormatList.Analyze(var AFormatString: String;
+ var ANumFormat: TsNumberFormat; var ADecimals: Word);
+const
+ SHORT_LONG_DATE: array[boolean] of TsNumberFormat = (
+ nfShortDate, nfLongDate
+ );
+ AMPM_SHORT_LONG_TIME: array[boolean, boolean] of TsNumberFormat = (
+ (nfShortTime, nfLongTime),
+ (nfShortTimeAM, nfLongTimeAM)
+ );
+ EXP_SCI: array[boolean] of TsNumberFormat = (
+ nfExp, nfSci
+ );
+var
+ decs: Word;
+ isAMPM: Boolean;
+ isLongTime: Boolean;
+ isLongDate: Boolean;
+ isInterval: Boolean;
+ isSci: Boolean;
+ isTime, isDate: Boolean;
+begin
+ ANumFormat := nfGeneral;
+ if IsPercentNumberFormat(AFormatString, ADecimals) then
+ ANumFormat := nfPercentage
+ else
+ if IsExpNumberFormat(AFormatstring, ADecimals, isSci) then
+ ANumFormat := EXP_SCI[isSci]
+ else
+ if IsThousandSepNumberFormat(AFormatString, ADecimals) then
+ ANumFormat := nfFixedTh
+ else
+ if IsFixedNumberFormat(AFormatString, ADecimals) then
+ ANumFormat := nfFixed
+ else begin
+ isTime := IsTimeFormat(AFormatString, isLongTime, isAMPM, isInterval, ADecimals);
+ isDate := IsDateFormat(AFormatString, isLongDate);
+ if isInterval then
+ ANumFormat := nfTimeInterval
+ else
+ if isDate and isTime then
+ ANumFormat := nfShortDateTime
+ else if isDate then
+ ANumFormat := SHORT_LONG_DATE[isLongDate]
+ else if isTime then
+ ANumFormat := AMPM_SHORT_LONG_TIME[isAMPM, isLongTime]
+ else if AFormatString <> '' then
+ ANumFormat := nfCustom;
+ end;
+end;
+
+{ Called from the reader when a format item has been read from the file.
+ Determines the numFormat type, format string etc and stores the format in the
+ list. If necessary, the format string has to be made compatible with fpc
+ afterwards - it is used directly for getting the cell text. }
+procedure TsCustomNumFormatList.AnalyzeAndAdd(AFormatIndex: Integer;
+ AFormatString: String);
+var
+ nf: TsNumberFormat;
+ decs: Word;
+begin
+ if Find(AFormatIndex) > -1 then
+ raise Exception.Create('TsCustomNumFormatList.AnalyzeAndAdd: Format index must be unique.');
+
+ // Analyze the format string and extract information for internal formatting
+ Analyze(AFormatString, nf, decs);
+
+ // Add the new item
+ AddFormat(AFormatIndex, nf, AFormatString, decs);
+end;
+
+{ Clears the list and frees memory occupied by the format items. }
+procedure TsCustomNumFormatList.Clear;
+var
+ i: Integer;
+begin
+ for i:=0 to Count-1 do RemoveFormat(i);
+ inherited Clear;
+end;
+
+{ Deletes a format item from the list, and makes sure that its memory is
+ released. }
+procedure TsCustomNumFormatList.Delete(AIndex: Integer);
+begin
+ RemoveFormat(AIndex);
+ Delete(AIndex);
+end;
+
+{ Determines whether the format attributed to the given cell is already
+ contained in the list and returns its list index. }
+function TsCustomNumFormatList.Find(AFormatCell: PCell): integer;
+begin
+ if AFormatCell = nil then
+ Result := -1
+ else
+ Result := Find(AFormatCell^.NumberFormat, AFormatCell^.NumberFormatStr, AFormatCell^.NumberDecimals);
+end;
+
+{ Seeks a format item with the given properties and returns its list index,
+ or -1 if not found. }
+function TsCustomNumFormatList.Find(ANumFormat: TsNumberFormat;
+ AFormatString: String; ADecimals: Integer): Integer;
+var
+ item: TsNumFormatData;
+ fmt: String;
+ itemfmt: String;
+begin
+ // These are pre-defined formats - no need to check format string & decimals
+ if ANumFormat in [ nfGeneral, nfShortDateTime, nfShortDate, nfLongDate,
+ nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM ]
+ then
+ for Result := 0 to Count-1 do begin
+ item := Items[Result];
+ if (item <> nil) and (item.NumFormat = ANumFormat) then
+ exit;
+ end
+ else
+ if (ANumFormat = nfFmtDateTime) then begin
+ fmt := lowercase(AFormatString);
+ for Result := 0 to Count-1 do begin
+ item := Items[Result];
+ if (item <> nil) and (item.NumFormat = nfFmtDateTime) then begin
+ itemfmt := lowercase(item.FormatString);
+ if ((itemfmt = 'dm') or (itemfmt = 'd-mmm') or (itemfmt = 'd mmm') or (itemfmt = 'd. mmm') or (itemfmt ='d/mmm'))
+ and ((fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm'))
+ then
+ exit;
+ if ((itemfmt = 'my') or (itemfmt = 'mmm-yy') or (itemfmt = 'mmm yyy') or (itemfmt = 'mmm/yy'))
+ and ((fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy'))
+ then
+ exit;
+ if ((itemfmt = 'ms') or (itemfmt = 'nn:ss') or (itemfmt = 'mm:ss'))
+ and ((fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss'))
+ then
+ exit;
+ if ((itemfmt = 'msz') or (itemfmt = 'mm:ss.z') or (itemfmt = 'mm:ss.0'))
+ and ((fmt = 'msz') or (fmt = 'mm:ss.z') or (fmt = 'mm:ss.0'))
+ then
+ exit;
+ end;
+ end;
+ for Result := 0 to Count-1 do begin
+ item := Items[Result];
+ if fmt = lowercase(item.FormatString) then
+ exit;
+ end;
+ end else
+ // Check only the format string for nfCustom.
+ if (ANumFormat = nfCustom) then begin
+ for Result := 0 to Count-1 do begin
+ item := Items[Result];
+ if (item <> nil)
+ and (item.NumFormat = ANumFormat)
+ and (item.FormatString = AFormatString)
+ then
+ exit;
+ end;
+ end else
+ // The other formats can carry additional information
+ for Result := 0 to Count-1 do begin
+ item := Items[Result];
+ if (item <> nil)
+ and (item.NumFormat = ANumFormat)
+ and (item.FormatString = AFormatString)
+ and (item.Decimals = ADecimals)
+ then
+ exit;
+ end;
+ Result := -1;
+end;
+
+{ Finds the item with the given format index and returns its index in
+ the format list. }
+function TsCustomNumFormatList.Find(AFormatIndex: Integer): integer;
+var
+ item: TsNumFormatData;
+begin
+ for Result := 0 to Count-1 do begin
+ item := Items[Result];
+ if item.Index = AFormatIndex then
+ exit;
+ end;
+ Result := -1;
+end;
+
+{ Determines the format string to be written into the spreadsheet file.
+ Needs to be overridden if the format strings are different from the fpc
+ convention. }
+function TsCustomNumFormatList.FormatStringForWriting(AIndex: Integer): String;
+var
+ item: TsNumFormatdata;
+begin
+ item := Items[AIndex];
+ if item <> nil then Result := item.FormatString else Result := '';
+end;
+
+function TsCustomNumFormatList.GetItem(AIndex: Integer): TsNumFormatData;
+begin
+ Result := TsNumFormatData(inherited Items[AIndex]);
+end;
+
+{ Deletes the memory occupied by the formatting data, but keeps the item in then
+ list to maintain the indexes of followint items. }
+procedure TsCustomNumFormatList.RemoveFormat(AIndex: Integer);
+var
+ item: TsNumFormatData;
+begin
+ item := GetItem(AIndex);
+ if item <> nil then begin
+ item.Free;
+ SetItem(AIndex, nil);
+ end;
+end;
+
+procedure TsCustomNumFormatList.SetItem(AIndex: Integer; AValue: TsNumFormatData);
+begin
+ inherited Items[AIndex] := AValue;
+end;
+
+function CompareNumFormatData(Item1, Item2: Pointer): Integer;
+begin
+ Result := CompareValue(TsNumFormatData(Item1).Index, TsNumFormatData(Item2).Index);
+end;
+
+{ Sorts the format data items in ascending order of the format indexes. }
+procedure TsCustomNumFormatList.Sort;
+begin
+ inherited Sort(@CompareNumFormatData);
+end;
+
{ TsCustomSpreadReader }
constructor TsCustomSpreadReader.Create(AWorkbook: TsWorkbook);
begin
inherited Create;
FWorkbook := AWorkbook;
+ CreateNumFormatList;
+end;
+
+destructor TsCustomSpreadReader.Destroy;
+begin
+ FNumFormatList.Free;
+ inherited Destroy;
end;
{@@
@@ -2471,6 +2809,13 @@ constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
begin
inherited Create;
FWorkbook := AWorkbook;
+ CreateNumFormatList;
+end;
+
+destructor TsCustomSpreadWriter.Destroy;
+begin
+ FNumFormatList.Free;
+ inherited Destroy;
end;
{@@
@@ -2522,10 +2867,10 @@ begin
if uffNumberFormat in AFormat^.UsedFormattingFields then begin
if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue;
case AFormat^.NumberFormat of
- nfFixed, nfFixedTh, nfPercentage, nfExp:
+ nfFixed, nfFixedTh, nfPercentage, nfExp, nfSci:
if (FFormattingStyles[i].NumberDecimals <> AFormat^.NumberDecimals) then Continue;
- nfShortDate, nfShortDateTime, nfShortTime, nfLongTime, nfShortTimeAM,
- nfLongTimeAM, nfFmtDateTime, nfTimeInterval:
+ nfShortDate, nfLongDate, nfShortDateTime, nfShortTime, nfLongTime,
+ nfShortTimeAM, nfLongTimeAM, nfFmtDateTime, nfTimeInterval, nfCustom:
if (FFormattingstyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue;
end;
end;
@@ -2538,6 +2883,20 @@ begin
end;
end;
+{ If formatting features of a cell are not supported by the destination file
+ format of the writer, here is the place to apply replacements.
+ Must be overridden by descendants. See BIFF2 }
+procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
+var
+ isLong, isAMPM, isInterval: Boolean;
+ decs: Word;
+begin
+ if ACell^.NumberFormat = nfFmtDateTime then begin
+ if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
+ ACell^.NumberDecimals := decs;
+ end;
+end;
+
{ Each descendent should define it's own default formats, if any.
Always add the normal, unformatted style first to speed up. }
procedure TsCustomSpreadWriter.AddDefaultFormats();
@@ -2550,8 +2909,9 @@ procedure TsCustomSpreadWriter.ListAllFormattingStylesCallback(ACell: PCell; ASt
var
Len: Integer;
begin
- if ACell^.UsedFormattingFields = [] then Exit;
+ FixFormat(ACell);
+ if ACell^.UsedFormattingFields = [] then Exit;
if FindFormattingInList(ACell) <> -1 then Exit;
Len := Length(FFormattingStyles);
@@ -2575,6 +2935,30 @@ begin
end;
end;
+{@@
+ Adds the number format of the given cell to the NumFormatList, but only if
+ it does not yet exist in the list.
+}
+procedure TsCustomSpreadWriter.ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
+begin
+ FixFormat(ACell);
+ if FNumFormatList.Find(ACell) = -1 then
+ FNumFormatList.AddFormat(ACell);
+end;
+
+{@@
+ Iterats through all cells and collects the number formats in
+ FNumFormatList (without duplicates).
+ The index of the list item is needed for the field FormatIndex of the XF record. }
+procedure TsCustomSpreadWriter.ListAllNumFormats;
+var
+ i: Integer;
+begin
+ for i:=0 to Workbook.GetWorksheetCount-1 do
+ IterateThroughCells(nil, Workbook.GetWorksheetByIndex(i).Cells, ListAllNumFormatsCallback);
+ NumFormatList.Sort;
+end;
+
{@@
Expands a formula, separating it in it's constituent parts,
so that it is already partially parsed and it is easier to
diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas
index 7cec8c7ad..b761389aa 100644
--- a/components/fpspreadsheet/fpsutils.pas
+++ b/components/fpspreadsheet/fpsutils.pas
@@ -1,6 +1,10 @@
{
Utility functions and constants from FPSpreadsheet
}
+
+// to do: Remove the patched FormatDateTime when the feature of square brackets
+// in time format codes is in the rtl
+
unit fpsutils;
{$mode objfpc}{$H+}
@@ -59,8 +63,25 @@ function UTF8TextToXMLText(AText: ansistring): ansistring;
function TwipsToMillimeters(AValue: Integer): Single;
function MillimetersToTwips(AValue: Single): Integer;
+function IsExpNumberFormat(s: String; out Decimals: Word; out IsSci: Boolean): Boolean;
+function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
+function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
+function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
+function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
+function IsTimeFormat(s: String; out isLong, isAMPM, isInterval: Boolean;
+ out SecDecimals: Word): Boolean;
+
+function SciFloat(AValue: Double; ADecimals: Word): String;
+//function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
+procedure MakeTimeIntervalMask(Src: String; var Dest: String);
+
+function FormatDateTime(const FormatStr: string; DateTime: TDateTime): string;
+
implementation
+uses
+ Math;
+
{
Endianess helper functions
@@ -467,5 +488,663 @@ begin
Result := Round((AValue * 20 * 72) / 25.4);
end;
+
+{ Format checking procedures }
+
+{ This simple parsing procedure of the Excel format string checks for a fixed
+ float format s, i.e. s can be '0', '0.00', '000', '0,000', and returns the
+ number of decimals, i.e. number of zeros behind the decimal point }
+function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
+var
+ i: Integer;
+ p: Integer;
+ decs: String;
+begin
+ Decimals := 0;
+
+ // Excel time formats with milliseconds ("mm:ss.000") can be incorrectly
+ // detected as fixed number formats. Check this case at first.
+ if pos('s.0', s) > 0 then begin
+ Result := false;
+ exit;
+ end;
+
+ // Check if s is a valid format mask.
+ try
+ FormatFloat(s, 1.0);
+ except
+ on EConvertError do begin
+ Result := false;
+ exit;
+ end;
+ end;
+
+ // If it is count the zeros - each one is a decimal.
+ if s = '0' then
+ Result := true
+ else begin
+ p := pos('.', s); // position of decimal point;
+ if p = 0 then begin
+ Result := false;
+ end else begin
+ Result := true;
+ for i:= p+1 to Length(s) do
+ if s[i] = '0' then begin
+ inc(Decimals)
+ end
+ else
+ exit; // ignore characters after the last 0
+ end;
+ end;
+end;
+
+{ This function checks whether the format string corresponds to a thousand
+ separator format like "#,##0.000' and returns the number of fixed decimals
+ (i.e. zeros after the decimal point) }
+function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
+var
+ i, p: Integer;
+begin
+ Decimals := 0;
+
+ // Check if s is a valid format string
+ try
+ FormatFloat(s, 1.0);
+ except
+ on EConvertError do begin
+ Result := false;
+ exit;
+ end;
+ end;
+
+ // If it is look for the thousand separator. If found count decimals.
+ Result := (Pos(',', s) > 0);
+ if Result then begin
+ p := pos('.', s);
+ if p > 0 then
+ for i := p+1 to Length(s) do
+ if s[i] = '0' then
+ inc(Decimals)
+ else
+ exit; // ignore format characters after the last 0
+ end;
+end;
+
+{ This function checks whether the format string corresponds to percent
+ formatting and determines the number of decimals }
+function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
+var
+ i, p: Integer;
+begin
+ Decimals := 0;
+ // The signature of the percent format is a percent sign at the end of the
+ // format string.
+ Result := (s <> '') and (s[Length(s)] = '%');
+ if Result then begin
+ // Check for a valid format string
+ try
+ FormatDateTime(s, 1.0);
+ except
+ on EConvertError do begin
+ Result := false;
+ exit;
+ end;
+ end;
+ // Count decimals
+ p := pos('.', s);
+ if p > 0 then
+ for i := p+1 to Length(s)-1 do
+ if s[i] = '0' then
+ inc(Decimals)
+ else
+ exit; // ignore characters after last 0
+ end;
+end;
+
+{ This function checks whether the format string corresponds to exponential
+ formatting and determines the number of decimals. If it contains a # character
+ the function assumes a "scientific" format rounding the exponent to multiples
+ of 2. }
+function IsExpNumberFormat(s: String; out Decimals: Word;
+ out IsSci: Boolean): Boolean;
+var
+ i, pdp, pe, ph: Integer;
+begin
+ Result := false;
+ Decimals := 0;
+ IsSci := false;
+
+ if SameText(s, 'General') then
+ exit;
+
+ // Check for a valid format string
+ try
+ FormatDateTime(s, 1.0);
+ except
+ on EConvertError do begin
+ exit;
+ end;
+ end;
+
+ pe := pos('e', lowercase(s));
+ result := pe > 0;
+ if Result then begin
+ // The next character must be a "+", "-", or "0"
+ if (pe = Length(s)) or not (s[pe+1] in ['+', '-', '0']) then begin
+ Result := false;
+ exit;
+ end;
+ // Count decimals
+ pdp := pos('.', s);
+ if (pdp > 0) then begin
+ if pdp < pe then
+ for i:=pdp+1 to pe-1 do
+ if s[i] = '0' then
+ inc(Decimals)
+ else
+ break; // ignore characters after last 0
+ end;
+ // Look for hash signs # as indicator of the "scientific" format
+ ph := pos('#', s);
+ if ph > 0 then IsSci := true;
+ end;
+end;
+
+{ IsDateFormat checks if the format string s corresponds to a date format }
+function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
+begin
+ // Day, month, year are separated by a slash
+ Result := (pos('/', s) > 0);
+ if Result then
+ // Check validity of format string
+ try
+ FormatDateTime(s, now);
+ s := Lowercase(s);
+ isLong := (pos('mmm', s) <> 0) or (pos('mmmm', s) <> 0);
+ except on EConvertError do
+ Result := false;
+ end;
+end;
+
+{ IsTimeFormat checks if the format string s is a time format. isLong is
+ true if the string contains hours, minutes and seconds (two colons).
+ isAMPM is true if the string contains "AM/PM", "A/P" or "AMPM".
+ isInterval is true if the string contains square bracket codes for time intervals.
+ SecDecimals is the number of decimals for the seconds. }
+function IsTimeFormat(s: String; out isLong, isAMPM, isInterval: Boolean;
+ out SecDecimals: Word): Boolean;
+var
+ p, pdp, i, count: Integer;
+begin
+ isLong := false;
+ isAMPM := false;
+ SecDecimals := 0;
+
+ // Time parts are separated by a colon
+ p := pos(':', s);
+ result := p > 0;
+
+ if Result then begin
+ count := 1;
+ s := Uppercase(s);
+
+ // If there are is a second colon s is a "long" time format
+ for i:=p+1 to Length(s) do
+ if s[i] = ':' then begin
+ isLong := true;
+ break;
+ end;
+
+ // Seek for "AM/PM" etc to detect that specific format
+ isAMPM := (pos('AM/PM', s) > 0) or (pos('A/P', s) > 0) or (pos('AMPM', s) > 0);
+
+ // Look for square brackets indicating the interval format.
+ p := pos('[', s);
+ if p > 0 then isInterval := (pos(']', s) > 0) else isInterval := false;
+
+ // Count decimals
+ pdp := pos('.', s);
+ if (pdp > 0) then
+ for i:=pdp+1 to Length(s) do
+ if (s[i] in ['0', 'z', 'Z']) then
+ inc(SecDecimals)
+ else
+ break; // ignore characters after last 0
+
+ // Check validity of format string
+ try
+ FormatDateTime(s, now);
+ except on EConvertError do
+ Result := false;
+ end;
+ end;
+end;
+
+{ Formats the number AValue in "scientific" format with the given number of
+ decimals. "Scientific" is the same as "exponential", but with exponents rounded
+ to multiples of 3 (like for "kilo" - "Mega" - "Giga" etc.). }
+function SciFloat(AValue: Double; ADecimals: Word): String;
+var
+ m: Double;
+ ex: Integer;
+begin
+ if AValue = 0 then
+ Result := '0.0'
+ else begin
+ ex := floor(log10(abs(AValue))); // exponent
+ // round exponent to multiples of 3
+ ex := (ex div 3) * 3;
+ if ex < 0 then dec(ex, 3);
+ m := AValue * Power(10, -ex); // mantisse
+ Result := Format('%.*fE%d', [ADecimals, m, ex]);
+ end;
+end;
+ (*
+{ Formats the number AValue as a time string according to the format string.
+ If the hour part is between square brackets it can be greater than 24 hours.
+ Dto for the minutes or seconds part, with the higher-value part being added
+ and no longer being shown explicitly.
+ Example:
+ AValue = 1:30:02, FormatStr = "[mm]:ss]" --> "90:02" }
+function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
+var
+ hrs, mins, secs: Integer;
+ diff: Double;
+ h,m,s,z: Word;
+ ts: String;
+ fmt: String;
+ p: Integer;
+begin {
+ fmt := Lowercase(AFormatStr);
+ p := pos('h]', fmt);
+ if p > 0 then begin
+ System.Delete(fmt, 1, p+2);
+ Result := FormatDateTime(fmt, AValue);
+ DecodeTime(frac(abs(AValue)), h, m, s, z);
+ hrs := h + trunc(abs(AValue))*24;
+ Result := FormatDateTime(fmt, AValue);
+ end;
+ for i
+ p := pos('h
+ }
+ ts := DefaultFormatSettings.TimeSeparator;
+ DecodeTime(frac(abs(AValue)), h, m, s, z);
+ hrs := h + trunc(abs(AValue))*24;
+ if z > 499 then inc(s);
+ if hrs > 0 then
+ Result := Format('%d%s%.2d%s%.2d', [hrs, ts, m, ts, s])
+ else
+ Result := Format('%d%s%.2d', [m, ts, s]);
+ if AValue < 0.0 then Result := '-' + Result;
+end;
+ *)
+{ Creates a "time interval" format string having the first code identifier
+ in square brackets. }
+procedure MakeTimeIntervalMask(Src: String; var Dest: String);
+var
+ L: TStrings;
+begin
+ L := TStringList.Create;
+ try
+ L.StrictDelimiter := true;
+ L.Delimiter := ':';
+ L.DelimitedText := Src;
+ if L[0][1] <> '[' then L[0] := '[' + L[0];
+ if L[0][Length(L[0])] <> ']' then L[0] := L[0] + ']';
+ Dest := L.DelimitedText;
+ finally
+ L.Free;
+ end;
+end;
+
+
+{******************************************************************************}
+{******************************************************************************}
+{ Patch for SysUtils.FormatDateTime }
+{ Remove when the feature of square brackets in time format masks is in rtl }
+{******************************************************************************}
+{******************************************************************************}
+
+// Copied from "fpc/rtl/objpas/sysutils/datei.inc"
+procedure DateTimeToString(out Result: string; const FormatStr: string; const DateTime: TDateTime; const FormatSettings: TFormatSettings);
+var
+ ResultLen: integer;
+ ResultBuffer: array[0..255] of char;
+ ResultCurrent: pchar;
+
+{$IFDEF MSWindows}
+ isEnable_E_Format : Boolean;
+ isEnable_G_Format : Boolean;
+ eastasiainited : boolean;
+{$ENDIF MSWindows}
+
+(* This part is in the original code. It is not needed here and avoids a
+ dependency on the unit Windows.
+
+{$IFDEF MSWindows}
+ procedure InitEastAsia;
+ var ALCID : LCID;
+ PriLangID , SubLangID : Word;
+
+ begin
+ ALCID := GetThreadLocale;
+ PriLangID := ALCID and $3FF;
+ if (PriLangID>0) then
+ SubLangID := (ALCID and $FFFF) shr 10
+ else
+ begin
+ PriLangID := SysLocale.PriLangID;
+ SubLangID := SysLocale.SubLangID;
+ end;
+ isEnable_E_Format := (PriLangID = LANG_JAPANESE)
+ or
+ (PriLangID = LANG_KOREAN)
+ or
+ ((PriLangID = LANG_CHINESE)
+ and
+ (SubLangID = SUBLANG_CHINESE_TRADITIONAL)
+ );
+ isEnable_G_Format := (PriLangID = LANG_JAPANESE)
+ or
+ ((PriLangID = LANG_CHINESE)
+ and
+ (SubLangID = SUBLANG_CHINESE_TRADITIONAL)
+ );
+ eastasiainited :=true;
+ end;
+{$ENDIF MSWindows}
+*)
+ procedure StoreStr(Str: PChar; Len: Integer);
+ begin
+ if ResultLen + Len < SizeOf(ResultBuffer) then
+ begin
+ StrMove(ResultCurrent, Str, Len);
+ ResultCurrent := ResultCurrent + Len;
+ ResultLen := ResultLen + Len;
+ end;
+ end;
+
+ procedure StoreString(const Str: string);
+ var Len: integer;
+ begin
+ Len := Length(Str);
+ if ResultLen + Len < SizeOf(ResultBuffer) then
+ begin
+ StrMove(ResultCurrent, pchar(Str), Len);
+ ResultCurrent := ResultCurrent + Len;
+ ResultLen := ResultLen + Len;
+ end;
+ end;
+
+ procedure StoreInt(Value, Digits: Integer);
+ var
+ S: string[16];
+ Len: integer;
+ begin
+ System.Str(Value:Digits, S);
+ for Len := 1 to Length(S) do
+ begin
+ if S[Len] = ' ' then
+ S[Len] := '0'
+ else
+ Break;
+ end;
+ StoreStr(pchar(@S[1]), Length(S));
+ end ;
+
+var
+ Year, Month, Day, DayOfWeek, Hour, Minute, Second, MilliSecond: word;
+
+
+ procedure StoreFormat(const FormatStr: string; Nesting: Integer; TimeFlag: Boolean);
+ var
+ Token, lastformattoken, prevlasttoken: char;
+ FormatCurrent: pchar;
+ FormatEnd: pchar;
+ Count: integer;
+ Clock12: boolean;
+ P: pchar;
+ tmp: integer;
+ isInterval: Boolean;
+
+ begin
+ if Nesting > 1 then // 0 is original string, 1 is included FormatString
+ Exit;
+
+ FormatCurrent := PChar(FormatStr);
+ FormatEnd := FormatCurrent + Length(FormatStr);
+ Clock12 := false;
+ isInterval := false;
+ P := FormatCurrent;
+ // look for unquoted 12-hour clock token
+ while P < FormatEnd do
+ begin
+ Token := P^;
+ case Token of
+ '''', '"':
+ begin
+ Inc(P);
+ while (P < FormatEnd) and (P^ <> Token) do
+ Inc(P);
+ end;
+ 'A', 'a':
+ begin
+ if (StrLIComp(P, 'A/P', 3) = 0) or
+ (StrLIComp(P, 'AMPM', 4) = 0) or
+ (StrLIComp(P, 'AM/PM', 5) = 0) then
+ begin
+ Clock12 := true;
+ break;
+ end;
+ end;
+ end; // case
+ Inc(P);
+ end ;
+ token := #255;
+ lastformattoken := ' ';
+ prevlasttoken := 'H';
+ while FormatCurrent < FormatEnd do
+ begin
+ Token := UpCase(FormatCurrent^);
+ Count := 1;
+ P := FormatCurrent + 1;
+ case Token of
+ '''', '"':
+ begin
+ while (P < FormatEnd) and (p^ <> Token) do
+ Inc(P);
+ Inc(P);
+ Count := P - FormatCurrent;
+ StoreStr(FormatCurrent + 1, Count - 2);
+ end ;
+ 'A':
+ begin
+ if StrLIComp(FormatCurrent, 'AMPM', 4) = 0 then
+ begin
+ Count := 4;
+ if Hour < 12 then
+ StoreString(FormatSettings.TimeAMString)
+ else
+ StoreString(FormatSettings.TimePMString);
+ end
+ else if StrLIComp(FormatCurrent, 'AM/PM', 5) = 0 then
+ begin
+ Count := 5;
+ if Hour < 12 then StoreStr(FormatCurrent, 2)
+ else StoreStr(FormatCurrent+3, 2);
+ end
+ else if StrLIComp(FormatCurrent, 'A/P', 3) = 0 then
+ begin
+ Count := 3;
+ if Hour < 12 then StoreStr(FormatCurrent, 1)
+ else StoreStr(FormatCurrent+2, 1);
+ end
+ else
+ raise EConvertError.Create('Illegal character in format string');
+ end ;
+ '/': StoreStr(@FormatSettings.DateSeparator, 1);
+ ':': StoreStr(@FormatSettings.TimeSeparator, 1);
+ '[': isInterval := true;
+ ']': isInterval := false;
+ ' ', 'C', 'D', 'H', 'M', 'N', 'S', 'T', 'Y','Z' :
+ begin
+ while (P < FormatEnd) and (UpCase(P^) = Token) do
+ Inc(P);
+ Count := P - FormatCurrent;
+ case Token of
+ ' ': StoreStr(FormatCurrent, Count);
+ 'Y': begin
+ if Count > 2 then
+ StoreInt(Year, 4)
+ else
+ StoreInt(Year mod 100, 2);
+ end;
+ 'M': begin
+ if isInterval and ((prevlasttoken = 'H') or TimeFlag) then
+ StoreInt(Minute + Hour*60 + trunc(DateTime)*24*60, 0)
+ else
+ if (lastformattoken = 'H') or TimeFlag then
+ begin
+ if Count = 1 then
+ StoreInt(Minute, 0)
+ else
+ StoreInt(Minute, 2);
+ end
+ else
+ begin
+ case Count of
+ 1: StoreInt(Month, 0);
+ 2: StoreInt(Month, 2);
+ 3: StoreString(FormatSettings.ShortMonthNames[Month]);
+ else
+ StoreString(FormatSettings.LongMonthNames[Month]);
+ end;
+ end;
+ end;
+ 'D': begin
+ case Count of
+ 1: StoreInt(Day, 0);
+ 2: StoreInt(Day, 2);
+ 3: StoreString(FormatSettings.ShortDayNames[DayOfWeek]);
+ 4: StoreString(FormatSettings.LongDayNames[DayOfWeek]);
+ 5: StoreFormat(FormatSettings.ShortDateFormat, Nesting+1, False);
+ else
+ StoreFormat(FormatSettings.LongDateFormat, Nesting+1, False);
+ end ;
+ end ;
+ 'H':
+ if isInterval then
+ StoreInt(Hour + trunc(DateTime)*24, 0)
+ else
+ if Clock12 then
+ begin
+ tmp := hour mod 12;
+ if tmp=0 then tmp:=12;
+ if Count = 1 then
+ StoreInt(tmp, 0)
+ else
+ StoreInt(tmp, 2);
+ end
+ else begin
+ if Count = 1 then
+ StoreInt(Hour, 0)
+ else
+ StoreInt(Hour, 2);
+ end;
+ 'N': if isInterval then
+ StoreInt(Minute + 60*Hour + 60*24*trunc(DateTime), 0)
+ else
+ if Count = 1 then
+ StoreInt(Minute, 0)
+ else
+ StoreInt(Minute, 2);
+ 'S': if isInterval then
+ StoreInt(Second + Minute*60 + Hour*60*60 + trunc(DateTime)*24*60*60, 0)
+ else
+ if Count = 1 then
+ StoreInt(Second, 0)
+ else
+ StoreInt(Second, 2);
+ 'Z': if Count = 1 then
+ StoreInt(MilliSecond, 0)
+ else
+ StoreInt(MilliSecond, 3);
+ 'T': if Count = 1 then
+ StoreFormat(FormatSettings.ShortTimeFormat, Nesting+1, True)
+ else
+ StoreFormat(FormatSettings.LongTimeFormat, Nesting+1, True);
+ 'C': begin
+ StoreFormat(FormatSettings.ShortDateFormat, Nesting+1, False);
+ if (Hour<>0) or (Minute<>0) or (Second<>0) then
+ begin
+ StoreString(' ');
+ StoreFormat(FormatSettings.LongTimeFormat, Nesting+1, True);
+ end;
+ end;
+
+(* This part is in the original code. It is not needed here and avoids a
+ dependency on the unit Windows.
+
+{$IFDEF MSWindows}
+ 'E':
+ begin
+ if not Eastasiainited then InitEastAsia;
+ if Not(isEnable_E_Format) then StoreStr(@FormatCurrent^, 1)
+ else
+ begin
+ while (P < FormatEnd) and (UpCase(P^) = Token) do
+ P := P + 1;
+ Count := P - FormatCurrent;
+ StoreString(ConvertEraYearString(Count,Year,Month,Day));
+ end;
+ lastformattoken:=token;
+ end;
+ 'G':
+ begin
+ if not Eastasiainited then InitEastAsia;
+ if Not(isEnable_G_Format) then StoreStr(@FormatCurrent^, 1)
+ else
+ begin
+ while (P < FormatEnd) and (UpCase(P^) = Token) do
+ P := P + 1;
+ Count := P - FormatCurrent;
+ StoreString(ConvertEraString(Count,Year,Month,Day));
+ end;
+ lastformattoken:=token;
+ end;
+{$ENDIF MSWindows}
+*)
+ end;
+ prevlasttoken := lastformattoken;
+ lastformattoken := token;
+ end;
+ else
+ StoreStr(@Token, 1);
+ end ;
+ Inc(FormatCurrent, Count);
+ end;
+ end;
+
+begin
+{$ifdef MSWindows}
+ eastasiainited:=false;
+{$endif MSWindows}
+ DecodeDateFully(DateTime, Year, Month, Day, DayOfWeek);
+ DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
+ ResultLen := 0;
+ ResultCurrent := @ResultBuffer[0];
+ if FormatStr <> '' then
+ StoreFormat(FormatStr, 0, False)
+ else
+ StoreFormat('C', 0, False);
+ ResultBuffer[ResultLen] := #0;
+ result := StrPas(@ResultBuffer[0]);
+end ;
+
+function FormatDateTime(const FormatStr: string; DateTime: TDateTime): string;
+begin
+ DateTimeToString(Result, FormatStr, DateTime, DefaultFormatSettings);
+end;
+
end.
diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas
index 014d67267..957028f52 100755
--- a/components/fpspreadsheet/xlsbiff2.pas
+++ b/components/fpspreadsheet/xlsbiff2.pas
@@ -38,6 +38,15 @@ uses
type
+ { TsBIFF2NumFormatList }
+ TsBIFF2NumFormatList = class(TsCustomNumFormatList)
+ protected
+ procedure AddBuiltinFormats; override;
+ public
+ constructor Create;
+ function FormatStringForWriting(AIndex: Integer): String; override;
+ end;
+
{ TsSpreadBIFF2Reader }
TsSpreadBIFF2Reader = class(TsSpreadBIFFReader)
@@ -47,6 +56,7 @@ type
FFont: TsFont;
protected
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); override;
+ procedure CreateNumFormatList; override;
procedure ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String); override;
@@ -80,9 +90,7 @@ type
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFontIndex: Integer);
procedure WriteFonts(AStream: TStream);
- procedure WriteFormat(AStream: TStream; AFormatCode: String);
procedure WriteFormatCount(AStream: TStream);
- procedure WriteFormats(AStream: TStream);
procedure WriteIXFE(AStream: TStream; XFIndex: Word);
procedure WriteXF(AStream: TStream; AFontIndex, AFormatIndex: byte;
ABorders: TsCellBorders = []; AHorAlign: TsHorAlignment = haLeft;
@@ -90,12 +98,17 @@ type
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
procedure WriteXFRecords(AStream: TStream);
protected
+ procedure CreateNumFormatList; override;
+ procedure FixFormat(ACell: PCell); override;
+ procedure ListAllNumFormats; override;
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override;
- procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); override;
+ procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
+ AListIndex: Integer); override;
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); override;
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); override;
procedure WriteRow(AStream: TStream; ASheet: TsWorksheet;
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); override;
+ procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); override;
procedure WriteWindow1(AStream: TStream); override;
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
public
@@ -116,7 +129,8 @@ var
$00FFFF // $07: cyan
);
- { These are the built-in number formats of BIFF 2. They are not stored in
+(*
+{ These are the built-in number formats of BIFF2. They are not stored in
the file. Note that, compared to the BUFF5+ built-in formats, two formats
are missing and the indexes are offset by 2 after #11.
It seems that BIFF2 can handle only these 21 formats. The other formats
@@ -145,6 +159,7 @@ var
'h:mm:ss',
'M/D/YY h:mm' // 20
);
+*)
implementation
@@ -177,7 +192,7 @@ const
INT_EXCEL_SHEET = $0010;
INT_EXCEL_CHART = $0020;
INT_EXCEL_MACRO_SHEET = $0040;
-
+ (*
{ FORMAT record constants for BIFF2 }
// Subset of the built-in formats for US Excel,
// including those needed for date/time output
@@ -206,6 +221,76 @@ const
FORMAT_TIME_MS = 19; //time MM:SS
FORMAT_TIME_MSZ = 19; //time MM:SS.0
FORMAT_TIME_INTERVAL = 19; //time [hh]:mm:ss, hh can be >24
+ *)
+
+{ TsBIFF2NumFormatList }
+
+constructor TsBIFF2NumFormatList.Create;
+begin
+ inherited Create;
+end;
+
+procedure TsBIFF2NumFormatList.AddBuiltinFormats;
+begin
+ AddFormat( 0, nfGeneral);
+ AddFormat( 1, nfFixed, '0', 0);
+ AddFormat( 2, nfFixed, '0.00', 2);
+ AddFormat( 3, nfFixedTh, '#,##0', 0);
+ AddFormat( 4, nfFixedTh, '#,##0.00', 2);
+ AddFormat( 5, nfFixedTh, '"$"#,##0_);("$"#,##0)', 0);
+ AddFormat( 6, nfFixedTh, '"$"#,##0_);[Red]("$"#,##0)', 2);
+ AddFormat( 7, nfFixedTh, '"$"#,##0.00_);("$"#,##0.00)', 0);
+ AddFormat( 8, nfFixedTh, '"$"#,##0.00_);[Red]("$"#,##0.00)', 2);
+ AddFormat( 9, nfPercentage, '0%', 0);
+ AddFormat(10, nfPercentage, '0.00%', 2);
+ AddFormat(11, nfExp, '0.00E+00', 2);
+ AddFormat(12, nfShortDate);
+ AddFormat(13, nfLongDate);
+ AddFormat(14, nfFmtDateTime, 'd-mmm');
+ AddFormat(15, nfFmtDateTime, 'mmm-yy');
+ AddFormat(16, nfShortTimeAM);
+ AddFormat(17, nfLongTimeAM);
+ AddFormat(18, nfShortTime);
+ AddFormat(19, nfLongTime);
+ AddFormat(20, nfShortDateTime);
+
+ FFirstFormatIndexInFile := 0; // BIFF2 stores built-in formats to file.
+ FNextFormatIndex := 21; // not needed - there are not user-defined formats
+end;
+
+{ Creates formatting strings that are written into the file. }
+function TsBIFF2NumFormatList.FormatStringForWriting(AIndex: Integer): String;
+var
+ ds, ts, cs: string;
+begin
+ ds := DefaultFormatSettings.DecimalSeparator;
+ ts := DefaultFormatSettings.ThousandSeparator;
+ cs := DefaultFormatSettings.CurrencyString;
+ case AIndex of
+ 0: Result := 'General';
+ 1: Result := '0';
+ 2: Result := '0' + ds + '00'; // 0.00
+ 3: Result := '#' + ts + '#0'; // #,##0
+ 4: Result := '#' + ts + '#0' + ds + '0'; // #,##0.00
+ 5: Result := UTF8ToAnsi(Format('"%s"#%s##0_);("%s"#%s##0)', [cs, ts, cs, ts]));
+ 6: Result := UTF8ToAnsi(Format('"%s"#%s##0_);[Red]("%s"#%s##0)', [cs, ts, cs, ts]));
+ 7: Result := UTF8ToAnsi(Format('"%s"#%s##0%s00_);("%s"#%s##0%s00)', [cs, ts, ds, cs, ts, ds]));
+ 8: Result := UTF8ToAnsi(Format('"%s"#%s##0%s00_);[Red]("%s"#%s##0%s00)', [cs, ts, ds, cs, ts, ds]));
+ 9: Result := '0%';
+ 10: Result := '0' + ds + '00%'; // 0.00%
+ 11: Result := '0' + ds + '00E+00'; // 0.00E+00
+ 12: Result := 'm/d/yy';
+ 13: Result := 'd-mmm-yy';
+ 14: Result := 'd-mmm';
+ 15: Result := 'mmm-yy';
+ 16: Result := 'h:mm AM/PM';
+ 17: Result := 'h:mm:ss AM/PM';
+ 18: Result := 'h:mm';
+ 19: Result := 'h:mm:ss';
+ 20: Result := 'm/d/yy h:mm';
+ end;
+end;
+
{ TsSpreadBIFF2Reader }
@@ -252,6 +337,14 @@ begin
end;
end;
+{ Creates the correct version of the number format list.
+ It is for BIFF2 and BIFF3 file formats. }
+procedure TsSpreadBIFF2Reader.CreateNumFormatList;
+begin
+ FreeAndNil(FNumFormatList);
+ FNumFormatList := TsBIFF2NumFormatList.Create;
+end;
+
{ Extracts the number format data from an XF record indexed by AXFIndex.
Note that BIFF2 supports only 21 formats. }
procedure TsSpreadBIFF2Reader.ExtractNumberFormat(AXFIndex: WORD;
@@ -270,7 +363,7 @@ const
2, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 11..20
);
var
- lFormatData: TFormatListData;
+ lNumFormatData: TsNumFormatData;
lXFData: TXFListData;
isAMPM: Boolean;
isLongTime: Boolean;
@@ -280,9 +373,9 @@ begin
ANumberFormat := nfGeneral;
ANumberFormatStr := '';
ADecimals := 0;
-
- lFormatData := FindFormatDataForCell(AXFIndex);
- if lFormatData = nil then begin
+ (*
+ lNumFormatData := FindNumFormatDataForCell(AXFIndex);
+ if lNumFormatData = nil then begin
// no custom format, so first test for default formats
lXFData := TXFListData (FXFList.Items[AXFIndex]);
if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 20) then begin
@@ -291,20 +384,20 @@ begin
end;
end else
// The next is copied from xlscommon - I think it's not necessary here
- if IsPercentNumberFormat(lFormatData.FormatString, ADecimals) then
+ if IsPercentNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfPercentage
else
- if IsExpNumberFormat(lFormatData.Formatstring, ADecimals) then
+ if IsExpNumberFormat(lNumFormatData.Formatstring, ADecimals) then
ANumberFormat := nfExp
else
- if IsThousandSepNumberFormat(lFormatData.FormatString, ADecimals) then
+ if IsThousandSepNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixedTh
else
- if IsFixedNumberFormat(lFormatData.FormatString, ADecimals) then
+ if IsFixedNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixed
else begin
- t := IsTimeFormat(lFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
- d := IsDateFormat(lFormatData.FormatString);
+ t := IsTimeFormat(lNumFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
+ d := IsDateFormat(lNumFormatData.FormatString, isLongDate);
if d and t then
ANumberFormat := nfShortDateTime
else
@@ -324,7 +417,7 @@ begin
ANumberFormat := nfShortTime;
end;
end;
- end;
+ end; *)
end;
procedure TsSpreadBIFF2Reader.ReadBlank(AStream: TStream);
@@ -696,6 +789,14 @@ end;
{ TsSpreadBIFF2Writer }
+{ Creates the correct version of the number format list.
+ It is for BIFF2 and BIFF3 file formats. }
+procedure TsSpreadBIFF2Writer.CreateNumFormatList;
+begin
+ FreeAndNil(FNumFormatList);
+ FNumFormatList := TsBIFF2NumFormatList.Create;
+end;
+
function TsSpreadBIFF2Writer.FindXFIndex(ACell: PCell): Word;
var
i: Integer;
@@ -712,6 +813,37 @@ begin
end;
end;
+procedure TsSpreadBIFF2Writer.FixFormat(ACell: PCell);
+var
+ j: Integer;
+begin
+ case ACell.NumberFormat of
+ nfExp:
+ if ACell.NumberDecimals <> 2 then begin
+ ACell.NumberDecimals := 2;
+ ACell.NumberFormatStr := '0.00E+00';
+ end;
+ nfSci:
+ begin
+ ACell.NumberFormat := nfExp;
+ ACell.NumberFormatStr := '0.00E+00';
+ ACell.NumberDecimals := 2;
+ end;
+ nfFmtDateTime:
+ begin
+ j := NumFormatList.Find(ACell);
+ if j = -1 then ACell.NumberFormat := nfLongTime;
+ end;
+ nfCustom:
+ ACell.NumberFormat := nfGeneral;
+ end;
+end;
+
+procedure TsSpreadBIFF2Writer.ListAllNumFormats;
+begin
+ // Nothing to do. All formats have already been added by the NumFormatList.
+end;
+
{
Attaches cell formatting data for the given cell to the current record.
Is called from all writing methods of cell contents.
@@ -825,6 +957,7 @@ begin
WriteBOF(AStream);
WriteFonts(AStream);
+ WriteFormatCount(AStream);
WriteFormats(AStream);
WriteXFRecords(AStream);
WriteColWidths(AStream);
@@ -940,7 +1073,7 @@ end;
procedure TsSpreadBIFF2Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var
- i: Integer;
+ i, j: Integer;
lFontIndex: Word;
lFormatIndex: Word; //number format
lBorders: TsCellBorders;
@@ -958,66 +1091,19 @@ begin
lHorAlign := FFormattingStyles[i].HorAlignment;
// Now apply the modifications.
- if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then
- case FFormattingStyles[i].NumberFormat of
- nfFixed:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_FIXED_0_DECIMALS;
- 2: lFormatIndex := FORMAT_FIXED_2_DECIMALS;
- end;
- nfFixedTh:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_FIXED_THOUSANDS_0_DECIMALS;
- 2: lFormatIndex := FORMAT_FIXED_THOUSANDS_2_DECIMALS;
- end;
- nfExp:
- lFormatIndex := FORMAT_EXP_2_DECIMALS;
- nfSci:
- lFormatIndex := FORMAT_SCI_1_DECIMAL;
- nfPercentage:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_PERCENT_0_DECIMALS;
- 2: lFormatIndex := FORMAT_PERCENT_2_DECIMALS;
- end;
+ if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
+ j := NumFormatList.Find(@FFormattingStyles[i]);
+ if j > -1 then begin
+ lFormatIndex := NumFormatList[j].Index;
{
- nfCurrency:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS;
- 2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS;
- end;
- }
- nfShortDate:
- lFormatIndex := FORMAT_SHORT_DATE;
- nfShortTime:
- lFormatIndex := FORMAT_SHORT_TIME;
- nfLongTime:
- lFormatIndex := FORMAT_LONG_TIME;
- nfShortTimeAM:
- lFormatIndex := FORMAT_SHORT_TIME_AM;
- nfLongTimeAM:
- lFormatIndex := FORMAT_LONG_TIME_AM;
- nfShortDateTime:
- lFormatIndex := FORMAT_SHORT_DATETIME;
- nfFmtDateTime:
- begin
- fmt := lowercase(FFormattingStyles[i].NumberFormatStr);
- if (fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm') then
- lFormatIndex := FORMAT_DATE_DM
- else
- if (fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy') then
- lFormatIndex := FORMAT_DATE_MY
- else
- { Because of limitations of BIFF2 the next two formats are mapped
- to the same format index! }
- if (fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss') then
- lFormatIndex := FORMAT_TIME_MS
- else
- if (fmt = 'msz') or (fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or (fmt = 'mm:ss.0') or (fmt = 'mm:ss.z') or (fmt = 'nn:ss.z') then
- lFormatIndex := FORMAT_TIME_MSZ;
- end;
- nfTimeInterval:
- lFormatIndex := FORMAT_TIME_INTERVAL;
+ // BIFF2 can only handle the 21 built-in formats. Here we find replacements
+ // for the others.
+ case NumFormatList[j].NumFormat of
+ nfSci : lFormatIndex := 11; // Exp
+ nfFmtDateTime : if lFormatIndex > 20 then lFormatIndex := 19;
+ end;}
end;
+ end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border;
@@ -1149,6 +1235,24 @@ begin
WriteFont(AStream, i);
end;
+procedure TsSpreadBiff2Writer.WriteFormat(AStream: TStream;
+ AFormatData: TsNumFormatData; AListIndex: Integer);
+var
+ len: Integer;
+ s: ansistring;
+begin
+ s := NumFormatList.FormatStringForWriting(AListIndex);
+ len := Length(s);
+
+ { BIFF Record header }
+ AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT));
+ AStream.WriteWord(WordToLE(1 + len));
+
+ { Format string }
+ AStream.WriteByte(len); // AnsiString, char count in 1 byte
+ AStream.WriteBuffer(s[1], len); // String data
+end;
+ (*
procedure TsSpreadBIFF2Writer.WriteFormat(AStream: TStream; AFormatCode: String);
var
len: Integer;
@@ -1167,15 +1271,15 @@ begin
{ Write format string }
AStream.WriteByte(len);
AStream.WriteBuffer(s[1], len);
-end;
+end; *)
procedure TsSpreadBIFF2Writer.WriteFormatCount(AStream: TStream);
begin
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMATCOUNT));
AStream.WriteWord(WordToLE(2));
- AStream.WriteWord(WordToLE(High(NUMFORMAT_BIFF2)+1));
+ AStream.WriteWord(WordToLE(21)); // there are 21 built-in formats
end;
-
+ (*
procedure TsSpreadBIFF2Writer.WriteFormats(AStream: TStream);
var
i: Integer;
@@ -1183,7 +1287,7 @@ begin
WriteFormatCount(AStream);
for i:=0 to High(NUMFORMAT_BIFF2) do
WriteFormat(AStream, NUMFORMAT_BIFF2[i]);
-end;
+end;*)
(*
var
ds, ts: Char; //decimal separator, thousand separator
diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas
index 51e217045..df73fe1e7 100755
--- a/components/fpspreadsheet/xlsbiff5.pas
+++ b/components/fpspreadsheet/xlsbiff5.pas
@@ -84,8 +84,6 @@ type
procedure ReadBlank(AStream: TStream); override;
procedure ReadFont(const AStream: TStream);
procedure ReadFormat(AStream: TStream); override;
- procedure ReadFormula(AStream: TStream); override;
- procedure ReadFormulaExcel(AStream: TStream);
procedure ReadLabel(AStream: TStream); override;
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
@@ -115,6 +113,8 @@ type
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream);
+ procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
+ AListIndex: Integer); override;
procedure WriteIndex(AStream: TStream);
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: string; ACell: PCell); override;
@@ -130,6 +130,7 @@ type
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
procedure WriteXFRecords(AStream: TStream);
public
+ constructor Create(AWorkbook: TsWorkbook); override;
{ General writing methods }
procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); override;
@@ -296,9 +297,21 @@ const
MASK_XF_BKGR_BACKGROUND_COLOR = $00003F80;
MASK_XF_BKGR_FILLPATTERN = $003F0000;
+ TEXT_ROTATIONS: Array[TsTextRotation] of Byte = (
+ XF_ROTATION_HORIZONTAL,
+ XF_ROTATION_90DEG_CW,
+ XF_ROTATION_90DEG_CCW,
+ XF_ROTATION_STACKED
+ );
+
{ TsSpreadBIFF5Writer }
+constructor TsSpreadBIFF5Writer.Create(AWorkbook: TsWorkbook);
+begin
+ inherited Create(AWorkbook);
+end;
+
{*******************************************************************
* TsSpreadBIFF5Writer.WriteToFile ()
*
@@ -362,6 +375,7 @@ begin
WriteCodepage(AStream, WorkBookEncoding);
WriteWindow1(AStream);
WriteFonts(AStream);
+ WriteFormats(AStream);
WritePalette(AStream);
WriteXFRecords(AStream);
WriteStyle(AStream);
@@ -632,6 +646,36 @@ begin
WriteFont(AStream, Workbook.GetFont(i));
end;
+{*******************************************************************
+* TsSpreadBIFF5Writer.WriteFormat
+*
+* DESCRIPTION: Writes an Excel 5 FORMAT record
+*
+*******************************************************************}
+procedure TsSpreadBiff5Writer.WriteFormat(AStream: TStream;
+ AFormatData: TsNumFormatData; AListIndex: Integer);
+var
+ len: Integer;
+ s: ansistring;
+begin
+ if (AFormatData = nil) or (AFormatData.FormatString = '') then
+ exit;
+
+ s := NumFormatList.FormatStringForWriting(AListIndex);
+ len := Length(s);
+
+ { BIFF Record header }
+ AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT));
+ AStream.WriteWord(WordToLE(2 + 1 + len * SizeOf(AnsiChar)));
+
+ { Format index }
+ AStream.WriteWord(WordToLE(AFormatData.Index));
+
+ { Format string }
+ AStream.WriteByte(len); // AnsiString, char count in 1 byte
+ AStream.WriteBuffer(s[1], len * SizeOf(AnsiChar)); // String data
+end;
+
{*******************************************************************
* TsSpreadBIFF5Writer.WriteRPNFormula ()
*
@@ -1047,7 +1091,7 @@ end;
procedure TsSpreadBIFF5Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var
- i: Integer;
+ i, j: Integer;
lFontIndex: Word;
lFormatIndex: Word; //number format
lTextRotation: Byte;
@@ -1073,77 +1117,17 @@ begin
lBackgroundColor := FFormattingStyles[i].BackgroundColor;
// Now apply the modifications.
- if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then
- case FFormattingStyles[i].NumberFormat of
- nfFixed:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_FIXED_0_DECIMALS;
- 2: lFormatIndex := FORMAT_FIXED_2_DECIMALS;
- end;
- nfFixedTh:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_FIXED_THOUSANDS_0_DECIMALS;
- 2: lFormatIndex := FORMAT_FIXED_THOUSANDS_2_DECIMALS;
- end;
- nfExp:
- lFormatIndex := FORMAT_EXP_2_DECIMALS;
- nfSci:
- lFormatIndex := FORMAT_SCI_1_DECIMAL;
- nfPercentage:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_PERCENT_0_DECIMALS;
- 2: lFormatIndex := FORMAT_PERCENT_2_DECIMALS;
- end;
- {
- nfCurrency:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS;
- 2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS;
- end;
- }
- nfShortDate:
- lFormatIndex := FORMAT_SHORT_DATE;
- nfShortTime:
- lFormatIndex := FORMAT_SHORT_TIME;
- nfLongTime:
- lFormatIndex := FORMAT_LONG_TIME;
- nfShortTimeAM:
- lFormatIndex := FORMAT_SHORT_TIME_AM;
- nfLongTimeAM:
- lFormatIndex := FORMAT_LONG_TIME_AM;
- nfShortDateTime:
- lFormatIndex := FORMAT_SHORT_DATETIME;
- nfFmtDateTime:
- begin
- fmt := lowercase(FFormattingStyles[i].NumberFormatStr);
- if (fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm') then
- lFormatIndex := FORMAT_DATE_DM
- else
- if (fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy') then
- lFormatIndex := FORMAT_DATE_MY
- else
- if (fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss') then
- lFormatIndex := FORMAT_TIME_MS
- else
- if (fmt = 'msz') or (fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or (fmt = 'mm:ss.0') or (fmt = 'mm:ss.z') or (fmt = 'nn:ss.z') then
- lFormatIndex := FORMAT_TIME_MSZ
- end;
- nfTimeInterval:
- lFormatIndex := FORMAT_TIME_INTERVAL;
- end;
+ if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
+ j := NumFormatList.Find(@FFormattingStyles[i]);
+ if j > -1 then
+ lFormatIndex := NumFormatList[j].Index;
+ end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border;
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
- begin
- case FFormattingStyles[i].TextRotation of
- trHorizontal : lTextRotation := XF_ROTATION_HORIZONTAL;
- rt90DegreeClockwiseRotation : lTextRotation := XF_ROTATION_90DEG_CW;
- rt90DegreeCounterClockwiseRotation : lTextRotation := XF_ROTATION_90DEG_CCW;
- rtStacked : lTextRotation := XF_ROTATION_STACKED;
- end;
- end;
+ lTextRotation := TEXT_ROTATIONS[FFormattingStyles[i].TextRotation];
if uffBold in FFormattingStyles[i].UsedFormattingFields then
lFontIndex := 1; // must be before uffFont which overrides uffBold
@@ -1270,7 +1254,7 @@ begin
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
- INT_EXCEL_ID_FORMULA : ReadFormulaExcel(AStream);
+ INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ;
@@ -1376,32 +1360,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF);
end;
-procedure TsSpreadBIFF5Reader.ReadFormulaExcel(AStream: TStream);
-var
- ARow, ACol: Cardinal;
- XF: WORD;
- ResultFormula: Double;
- Data: array [0..7] of BYTE;
- Flags: WORD;
- FormulaSize: BYTE;
-begin
- ReadRowColXF(AStream, ARow, ACol, XF);
-
- AStream.ReadBuffer(Data,Sizeof(Data));
- Flags:=WordLEtoN(AStream.ReadWord);
- AStream.ReadDWord; //Not used.
- FormulaSize:=AStream.ReadByte;
- //RPN data not used by now
- AStream.Position:=AStream.Position+FormulaSize;
-
- if SizeOf(Double)<>8 then Raise Exception.Create('Double is not 8 bytes');
- Move(Data[0],ResultFormula,sizeof(Data));
- FWorksheet.WriteNumber(ARow, ACol, ResultFormula);
-
- { Add attributes to cell }
- ApplyCellFormatting(ARow, ACol, XF);
-end;
-
procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
var
MemStream: TMemoryStream;
@@ -1638,12 +1596,10 @@ end;
// Read the FORMAT record for formatting numerical data
procedure TsSpreadBIFF5Reader.ReadFormat(AStream: TStream);
var
- lData: TFormatListData;
- str: AnsiString;
len: byte;
+ fmtIndex: Integer;
+ fmtString: AnsiString;
begin
- lData := TFormatListData.Create;
-
// Record FORMAT, BIFF 8 (5.49):
// Offset Size Contents
// 0 2 Format index used in other records
@@ -1651,21 +1607,15 @@ begin
// From BIFF5 on: indexes 0..163 are built in
// format index
- lData.Index := WordLEtoN(AStream.ReadWord);
+ fmtIndex := WordLEtoN(AStream.ReadWord);
// number format string
len := AStream.ReadByte;
- SetLength(str, len);
- AStream.ReadBuffer(str[1], len);
- lData.FormatString := str;
+ SetLength(fmtString, len);
+ AStream.ReadBuffer(fmtString[1], len);
// Add to the list
- FFormatList.Add(lData);
-end;
-
-procedure TsSpreadBIFF5Reader.ReadFormula(AStream: TStream);
-begin
-
+ NumFormatList.AnalyzeAndAdd(fmtIndex, fmtString);
end;
procedure TsSpreadBIFF5Reader.ReadLabel(AStream: TStream);
diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas
index e2bac5d07..bd73afa1d 100755
--- a/components/fpspreadsheet/xlsbiff8.pas
+++ b/components/fpspreadsheet/xlsbiff8.pas
@@ -89,7 +89,6 @@ type
procedure ReadFormat(AStream: TStream); override;
{ Record reading methods }
procedure ReadBlank(AStream: TStream); override;
- procedure ReadFormula(AStream: TStream); override;
procedure ReadLabel(AStream: TStream); override;
procedure ReadRichString(const AStream: TStream);
public
@@ -115,6 +114,8 @@ type
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream);
+ procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
+ AListIndex: Integer); override;
procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal;
const AFormula: TsFormula; ACell: PCell); override;
procedure WriteIndex(AStream: TStream);
@@ -131,6 +132,7 @@ type
AddBackground: Boolean = false; ABackgroundColor: TsColor = scSilver);
procedure WriteXFRecords(AStream: TStream);
public
+ constructor Create(AWorkbook: TsWorkbook); override;
{ General writing methods }
procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); override;
@@ -263,12 +265,24 @@ const
MASK_XF_BORDER_TOP_COLOR = $0000007F;
MASK_XF_BORDER_BOTTOM_COLOR = $00003F80;
+ TEXT_ROTATIONS: Array[TsTextRotation] of Byte = (
+ XF_ROTATION_HORIZONTAL,
+ XF_ROTATION_90DEG_CW,
+ XF_ROTATION_90DEG_CCW,
+ XF_ROTATION_STACKED
+ );
+
{ TsSpreadBIFF8Writer }
+constructor TsSpreadBIFF8Writer.Create(AWorkbook: TsWorkbook);
+begin
+ inherited Create(AWorkbook);
+end;
+
procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var
- i: Integer;
+ i, j: Integer;
lFontIndex: Word;
lFormatIndex: Word; //number format
lTextRotation: Byte;
@@ -281,7 +295,7 @@ var
lWordWrap: Boolean;
fmt: String;
begin
- // The first style was already added
+ // The first style was already added --> begin loop with 1
for i := 1 to Length(FFormattingStyles) - 1 do begin
// Default styles
lFontIndex := 0;
@@ -294,77 +308,17 @@ begin
lBackgroundColor := FFormattingStyles[i].BackgroundColor;
// Now apply the modifications.
- if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then
- case FFormattingStyles[i].NumberFormat of
- nfFixed:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_FIXED_0_DECIMALS;
- 2: lFormatIndex := FORMAT_FIXED_2_DECIMALS;
- end;
- nfFixedTh:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_FIXED_THOUSANDS_0_DECIMALS;
- 2: lFormatIndex := FORMAT_FIXED_THOUSANDS_2_DECIMALS;
- end;
- nfExp:
- lFormatIndex := FORMAT_EXP_2_DECIMALS;
- nfSci:
- lFormatIndex := FORMAT_SCI_1_DECIMAL;
- nfPercentage:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_PERCENT_0_DECIMALS;
- 2: lFormatIndex := FORMAT_PERCENT_2_DECIMALS;
- end;
- {
- nfCurrency:
- case FFormattingStyles[i].NumberDecimals of
- 0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS;
- 2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS;
- end;
- }
- nfShortDate:
- lFormatIndex := FORMAT_SHORT_DATE;
- nfShortTime:
- lFormatIndex := FORMAT_SHORT_TIME;
- nfLongTime:
- lFormatIndex := FORMAT_LONG_TIME;
- nfShortTimeAM:
- lFormatIndex := FORMAT_SHORT_TIME_AM;
- nfLongTimeAM:
- lFormatIndex := FORMAT_LONG_TIME_AM;
- nfShortDateTime:
- lFormatIndex := FORMAT_SHORT_DATETIME;
- nfFmtDateTime:
- begin
- fmt := lowercase(FFormattingStyles[i].NumberFormatStr);
- if (fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm') then
- lFormatIndex := FORMAT_DATE_DM
- else
- if (fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy') then
- lFormatIndex := FORMAT_DATE_MY
- else
- if (fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss') then
- lFormatIndex := FORMAT_TIME_MS
- else
- if (fmt = 'msz') or (fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or (fmt = 'mm:ss.0') or (fmt = 'mm:ss.z') or (fmt = 'nn:ss.z') then
- lFormatIndex := FORMAT_TIME_MSZ
- end;
- nfTimeInterval:
- lFormatIndex := FORMAT_TIME_INTERVAL;
- end;
+ if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
+ j := NumFormatList.Find(@FFormattingStyles[i]);
+ if j > -1 then
+ lFormatIndex := NumFormatList[j].Index;
+ end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border;
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
- begin
- case FFormattingStyles[i].TextRotation of
- trHorizontal: lTextRotation := XF_ROTATION_HORIZONTAL;
- rt90DegreeClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CW;
- rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CCW;
- rtStacked: lTextRotation := XF_ROTATION_STACKED;
- end;
- end;
+ lTextRotation := TEXT_ROTATIONS[FFormattingStyles[i].TextRotation];
if uffBold in FFormattingStyles[i].UsedFormattingFields then
lFontIndex := 1; // must be before uffFont which overrides uffBold
@@ -445,6 +399,7 @@ begin
WriteWindow1(AStream);
WriteFonts(AStream);
+ WriteFormats(AStream);
WritePalette(AStream);
WriteXFRecords(AStream);
WriteStyle(AStream);
@@ -713,6 +668,34 @@ begin
WriteFont(AStream, Workbook.GetFont(i));
end;
+procedure TsSpreadBiff8Writer.WriteFormat(AStream: TStream;
+ AFormatData: TsNumFormatData; AListIndex: Integer);
+var
+ len: Integer;
+ s: widestring;
+begin
+ if (AFormatData = nil) or (AFormatData.FormatString = '') then
+ exit;
+
+ s := NumFormatList.FormatStringForWriting(AListIndex);
+ len := Length(s);
+
+ { BIFF Record header }
+ AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT));
+ AStream.WriteWord(WordToLE(2 + 2 + 1 + len * SizeOf(WideChar)));
+
+ { Format index }
+ AStream.WriteWord(WordToLE(AFormatData.Index));
+
+ { Format string }
+ { - Unicodestring, char count in 2 bytes }
+ AStream.WriteWord(WordToLE(len));
+ { - Widestring flags, 1=regular unicode LE string }
+ AStream.WriteByte(1);
+ { - String data }
+ AStream.WriteBuffer(WideStringToLE(s)[1], len * Sizeof(WideChar));
+end;
+
{*******************************************************************
* TsSpreadBIFF8Writer.WriteFormula ()
*
@@ -1435,16 +1418,16 @@ begin
if RecordType <> INT_EXCEL_ID_CONTINUE then begin
case RecordType of
- INT_EXCEL_ID_BOF: ;
+ INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_BOUNDSHEET: ReadBoundSheet(AStream);
- INT_EXCEL_ID_EOF: SectionEOF := True;
- INT_EXCEL_ID_SST: ReadSST(AStream);
- INT_EXCEL_ID_CODEPAGE: ReadCodepage(AStream);
- INT_EXCEL_ID_FONT: ReadFont(AStream);
- INT_EXCEL_ID_XF: ReadXF(AStream);
- INT_EXCEL_ID_FORMAT: ReadFormat(AStream);
- INT_EXCEL_ID_DATEMODE: ReadDateMode(AStream);
- INT_EXCEL_ID_PALETTE: ReadPalette(AStream);
+ INT_EXCEL_ID_EOF : SectionEOF := True;
+ INT_EXCEL_ID_SST : ReadSST(AStream);
+ INT_EXCEL_ID_CODEPAGE : ReadCodepage(AStream);
+ INT_EXCEL_ID_FONT : ReadFont(AStream);
+ INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
+ INT_EXCEL_ID_XF : ReadXF(AStream);
+ INT_EXCEL_ID_DATEMODE : ReadDateMode(AStream);
+ INT_EXCEL_ID_PALETTE : ReadPalette(AStream);
else
// nothing
end;
@@ -1624,51 +1607,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF);
end;
-procedure TsSpreadBIFF8Reader.ReadFormula(AStream: TStream);
-var
- ARow, ACol: Cardinal;
- XF: WORD;
- ResultFormula: Double;
- Data: array [0..7] of BYTE;
- Flags: WORD;
- FormulaSize: BYTE;
- i: Integer;
-begin
- { BIFF Record header }
- { BIFF Record data }
- { Index to XF Record }
- ReadRowColXF(AStream, ARow, ACol, XF);
-
- { Result of the formula in IEE 754 floating-point value }
- AStream.ReadBuffer(Data, Sizeof(Data));
-
- { Options flags }
- Flags := WordLEtoN(AStream.ReadWord);
-
- { Not used }
- AStream.ReadDWord;
-
- { Formula size }
- FormulaSize := WordLEtoN(AStream.ReadWord);
-
- { Formula data, output as debug info }
-{ Write('Formula Element: ');
- for i := 1 to FormulaSize do
- Write(IntToHex(AStream.ReadByte, 2) + ' ');
- WriteLn('');}
-
- //RPN data not used by now
- AStream.Position := AStream.Position + FormulaSize;
-
- if SizeOf(Double) <> 8 then
- raise Exception.Create('Double is not 8 bytes');
- Move(Data[0], ResultFormula, SizeOf(Data));
- FWorksheet.WriteNumber(ARow, ACol, ResultFormula);
-
- {Add attributes}
- ApplyCellFormatting(ARow, ACol, XF);
-end;
-
procedure TsSpreadBIFF8Reader.ReadLabel(AStream: TStream);
var
L: Word;
@@ -1975,22 +1913,21 @@ end;
// Read the FORMAT record for formatting numerical data
procedure TsSpreadBIFF8Reader.ReadFormat(AStream: TStream);
var
- lData: TFormatListData;
+ fmtString: String;
+ fmtIndex: Integer;
begin
- lData := TFormatListData.Create;
-
// Record FORMAT, BIFF 8 (5.49):
// Offset Size Contents
// 0 2 Format index used in other records
// 2 var Number format string (Unicode string, 16-bit string length)
// From BIFF5 on: indexes 0..163 are built in
- lData.Index := WordLEtoN(AStream.ReadWord);
+ fmtIndex := WordLEtoN(AStream.ReadWord);
// 2 var. Number format string (Unicode string, 16-bit string length, ➜2.5.3)
- lData.FormatString := ReadWideString(AStream, False);
+ fmtString := ReadWideString(AStream, False);
// Add to the list
- FFormatList.Add(lData);
+ NumFormatList.AnalyzeAndAdd(fmtIndex, fmtString);
end;
diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas
index 53e22a4bb..66cd7b6fe 100644
--- a/components/fpspreadsheet/xlscommon.pas
+++ b/components/fpspreadsheet/xlscommon.pas
@@ -236,7 +236,7 @@ const
{ DATEMODE record, 5.28 }
DATEMODE_1900_BASE=1; //1/1/1900 minus 1 day in FPC TDateTime
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
-
+ (*
{ FORMAT record constants for BIFF5-BIFF8}
// Subset of the built-in formats for US Excel,
// including those needed for date/time output
@@ -262,6 +262,7 @@ const
FORMAT_TIME_INTERVAL = 46; //time [hh]:mm:ss, hh can be >24
FORMAT_TIME_MSZ = 47; //time MM:SS.0
FORMAT_SCI_1_DECIMAL = 48; //scientific, 1 decimal
+ *)
{ WINDOW1 record constants - BIFF5-BIFF8 }
MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001;
@@ -361,11 +362,12 @@ type
BackgroundColor: TsColor;
end;
- { Contents of the format record for BIFF5/8 }
- TFormatListData = class
+ { TsBIFFNumFormatList }
+ TsBIFFNumFormatList = class(TsCustomNumFormatList)
+ protected
+ procedure AddBuiltinFormats; override;
public
- Index: Integer;
- FormatString: widestring;
+ function FormatStringForWriting(AIndex: Integer): String; override;
end;
{ TsSpreadBIFFReader }
@@ -376,8 +378,8 @@ type
FDateMode: TDateMode;
FPaletteFound: Boolean;
FXFList: TFPList; // of TXFListData
- FFormatList: TFPList; // of TFormatListData
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual;
+ procedure CreateNumFormatList; override;
// Extracts a number out of an RK value
function DecodeRKValue(const ARK: DWORD): Double;
// Returns the numberformat for a given XF record
@@ -386,7 +388,7 @@ type
out ANumberFormatStr: String); virtual;
// Finds format record for XF record pointed to by cell
// Will not return info for built-in formats
- function FindFormatDataForCell(const AXFIndex: Integer): TFormatListData;
+ function FindNumFormatDataForCell(const AXFIndex: Integer): TsNumFormatData;
// Tries to find if a number cell is actually a date/datetime/time cell and retrieves the value
function IsDateTime(Number: Double; ANumberFormat: TsNumberFormat; var ADateTime: TDateTime): Boolean;
// Here we can add reading of records which didn't change across BIFF5-8 versions
@@ -397,6 +399,8 @@ type
procedure ReadDateMode(AStream: TStream);
// Read FORMAT record (cell formatting)
procedure ReadFormat(AStream: TStream); virtual;
+ // Read FORMULA record
+ procedure ReadFormula(AStream: TStream); override;
// Read multiple blank cells
procedure ReadMulBlank(AStream: TStream);
// Read multiple RK cells
@@ -428,6 +432,7 @@ type
FLastRow: Integer;
FLastCol: Word;
procedure AddDefaultFormats; override;
+ procedure CreateNumFormatList; override;
procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
@@ -453,6 +458,11 @@ type
// Writes out a TIME/DATE/TIMETIME
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: TDateTime; ACell: PCell); override;
+ // Writes out a FORMAT record
+ procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
+ AListIndex: Integer); virtual;
+ // Writes out all FORMAT records
+ procedure WriteFormats(AStream: TStream);
// Writes out a floating point NUMBER record
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: Double; ACell: PCell); override;
@@ -478,17 +488,38 @@ type
destructor Destroy; override;
end;
-function IsExpNumberFormat(s: String; out Decimals: Word): Boolean;
-function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
-function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
-function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
-
-function IsDateFormat(s: String): Boolean;
-function IsTimeFormat(s: String; out isLong, isAMPM, isMillisec: Boolean): Boolean;
-
implementation
+uses
+ StrUtils;
+
+const
+ { see ➜ 5.49 }
+ COUNT_DEFAULT_FORMATS = 58;
+ NOT_USED = nfGeneral;
+ DEFAULT_NUM_FORMATS: array[1..COUNT_DEFAULT_FORMATS] of TsNumberFormat = (
+ nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5
+ nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10
+ nfExp, NOT_USED, NOT_USED, nfShortDate, nfShortDate, // 11..15
+ nfFmtDateTime, nfFmtDateTime, nfShortTimeAM, nfLongTimeAM, nfShortTime, // 16..20
+ nfLongTime, nfShortDateTime, NOT_USED, NOT_USED, NOT_USED, // 21..25
+ NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 26..30
+ NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 31..35
+ NOT_USED, nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, // 36..40
+ nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, nfFmtDateTime, // 41..45
+ nfTimeInterval, nfFmtDateTime, nfSci, NOT_USED, NOT_USED, // 46..50
+ NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 51..55
+ NOT_USED, NOT_USED, NOT_USED // 56..58
+ );
+ DEFAULT_NUM_FORMAT_DECIMALS: array[1..COUNT_DEFAULT_FORMATS] of word = (
+ 0, 2, 0, 2, 0, 0, 2, 2, 0, 2, // 1..10
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11..20
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21..30
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, // 31..40
+ 0, 0, 2, 2, 0, 3, 0, 1, 0, 0, // 41..50 #48 is "scientific", use "exponential" instead
+ 0, 0, 0, 0, 0, 0, 0, 0); // 51..58
+
function ConvertExcelDateTimeToDateTime(
const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
begin
@@ -540,13 +571,75 @@ begin
end;
+{ TsBIFFNumFormatList }
+
+{ These are the built-in number formats as used by fpc. Before writing to file
+ some code will be modified to become compatible with Excel
+ (--> FormatStringForWriting) }
+procedure TsBIFFNumFormatList.AddBuiltinFormats;
+begin
+ AddFormat( 0, nfGeneral);
+ AddFormat( 1, nfFixed, '0', 0);
+ AddFormat( 2, nfFixed, '0.00', 2);
+ AddFormat( 3, nfFixedTh, '#,##0', 0);
+ AddFormat( 4, nfFixedTh, '#,##0.00', 2);
+ // 5..8 currently not supported
+ AddFormat( 9, nfPercentage, '0%', 0);
+ AddFormat(10, nfPercentage, '0.00%', 2);
+ AddFormat(11, nfExp, '0.00E+00', 2);
+ // fraction formats 12 ('# ?/?') and 13 ('# ??/??') not supported
+ AddFormat(14, nfShortDate);
+ AddFormat(15, nfLongDate);
+ AddFormat(16, nfFmtDateTime, 'D-MMM');
+ AddFormat(17, nfFmtDateTime, 'MMM-YY');
+ AddFormat(18, nfShortTimeAM);
+ AddFormat(19, nfLongTimeAM);
+ AddFormat(20, nfShortTime);
+ AddFormat(21, nfLongTime);
+ AddFormat(22, nfShortDateTime);
+ // 23..44 not supported
+ AddFormat(45, nfFmtDateTime, 'mm:ss');
+ AddFormat(46, nfTimeInterval, '[h]:mm:ss');
+ AddFormat(47, nfFmtDateTime, 'mm:ss.z'); // z will be replace by 0 later
+ AddFormat(48, nfSci, '##0.0E+0', 1);
+ // 49 ("Text") not supported
+
+ // All indexes from 0 to 163 are reserved for built-in formats.
+ // The first user-defined format starts at 164.
+ FFirstFormatIndexInFile := 164;
+ FNextFormatIndex := 164;
+end;
+
+{ Creates formatting strings that are written into the file. }
+function TsBIFFNumFormatList.FormatStringForWriting(AIndex: Integer): String;
+var
+ item: TsNumFormatData;
+ i: Integer;
+begin
+ Result := inherited FormatStringForWriting(AIndex);
+ item := Items[AIndex];
+ case item.NumFormat of
+ nfFmtDateTime:
+ begin
+ Result := lowercase(item.FormatString);
+ for i:=1 to Length(Result) do
+ if Result[i] in ['z', 'Z'] then Result[i] := '0';
+ end;
+ nfTimeInterval:
+ // Time interval format string could still be without square brackets
+ // if added by user.
+ // We check here for safety and add the brackets if not there.
+ MakeTimeIntervalMask(item.FormatString, Result);
+ end;
+end;
+
+
{ TsSpreadBIFFReader }
constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
FXFList := TFPList.Create;
- FFormatList := TFPList.Create;
// Initial base date in case it won't be read from file
FDateMode := dm1900;
end;
@@ -557,8 +650,6 @@ var
begin
for j := FXFList.Count-1 downto 0 do TObject(FXFList[j]).Free;
FXFList.Free;
- for j := FFormatList.Count-1 downto 0 do TObject(FFormatList[j]).Free;
- FFormatList.Free;
inherited Destroy;
end;
@@ -614,6 +705,15 @@ begin
end;
end;
+{ Creates the correct version of the number format list. It is for BIFF file
+ formats.
+ Valid for BIFF5.BIFF8. Needs to be overridden for BIFF2. }
+procedure TsSpreadBIFFReader.CreateNumFormatList;
+begin
+ FreeAndNil(FNumFormatList);
+ FNumFormatList := TsBIFFNumFormatList.Create;
+end;
+
{ Extracts a number out of an RK value.
Valid since BIFF3. }
function TsSpreadBIFFReader.DecodeRKValue(const ARK: DWORD): Double;
@@ -651,120 +751,51 @@ end;
procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String);
-const
- { see ➜ 5.49 }
- NOT_USED = nfGeneral;
- fmts: array[1..58] of TsNumberFormat = (
- nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5
- nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10
- nfExp, NOT_USED, NOT_USED, nfShortDate, nfShortDate, // 11..15
- nfFmtDateTime, nfFmtDateTime, nfShortTimeAM, nfLongTimeAM, nfShortTime, // 16..20
- nfLongTime, nfShortDateTime, NOT_USED, NOT_USED, NOT_USED, // 21..25
- NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 26..30
- NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 31..35
- NOT_USED, nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, // 36..40
- nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, nfFmtDateTime, // 41..45
- nfTimeInterval, nfFmtDateTime, nfSci, NOT_USED, NOT_USED, // 46..50
- NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 51..55
- NOT_USED, NOT_USED, NOT_USED // 56..58
- );
- decs: array[1..58] of word = (
- 0, 2, 0, 2, 0, 0, 2, 2, 0, 2, // 1..10
- 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11..20
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21..30
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, // 31..40
- 0, 0, 2, 2, 0, 3, 0, 1, 0, 0, // 41..50 #48 is "scientific", use "exponential" instead
- 0, 0, 0, 0, 0, 0, 0, 0); // 51..58
-var
- lFormatData: TFormatListData;
- lXFData: TXFListData;
- isAMPM: Boolean;
- isLongTime: Boolean;
- isMilliSec: Boolean;
- t,d: Boolean;
-begin
- ANumberFormat := nfGeneral;
- ANumberFormatStr := '';
- ADecimals := 0;
- lFormatData := FindFormatDataForCell(AXFIndex);
- {Record FORMAT, BIFF 5/8 (5.49):
- Offset Size Contents
- 0 2 Format index used in other records
- }
-
- if lFormatData = nil then begin
- // no custom format, so first test for default formats
- lXFData := TXFListData(FXFList.Items[AXFIndex]);
- case lXFData.FormatIndex of
- FORMAT_DATE_DM:
- begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'DM'; end;
- FORMAT_DATE_MY:
- begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'MY'; end;
- FORMAT_TIME_MS:
- begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'MS'; end;
- FORMAT_TIME_MSZ:
- begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'MSZ'; end;
- else
- if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 58) then begin
- ANumberFormat := fmts[lXFData.FormatIndex];
- ADecimals := decs[lXFData.FormatIndex];
+ procedure FixMilliseconds;
+ var
+ isLong, isAMPM, isInterval: Boolean;
+ decs: Word;
+ i: Integer;
+ begin
+ if IsTimeFormat(ANumberFormatStr, isLong, isAMPM, isInterval, decs)
+ and (decs > 0)
+ then
+ for i:= Length(ANumberFormatStr) downto 1 do
+ case ANumberFormatStr[i] of
+ '0': ANumberFormatStr[i] := 'z';
+ '.': break;
end;
- end;
- end else
- // Check custom formats if they have "/" in format string (this can fail for
- // custom text formats)
- if IsPercentNumberFormat(lFormatData.FormatString, ADecimals) then
- ANumberFormat := nfPercentage
- else
- if IsExpNumberFormat(lFormatData.Formatstring, ADecimals) then
- ANumberFormat := nfExp
- else
- if IsThousandSepNumberFormat(lFormatData.FormatString, ADecimals) then
- ANumberFormat := nfFixedTh
- else
- if IsFixedNumberFormat(lFormatData.FormatString, ADecimals) then
- ANumberFormat := nfFixed
- else begin
- t := IsTimeFormat(lFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
- d := IsDateFormat(lFormatData.FormatString);
- if d and t then
- ANumberFormat := nfShortDateTime
- else
- if d then
- ANumberFormat := nfShortDate
- else
- if t then begin
- if isAMPM then begin
- if isLongTime then
- ANumberFormat := nfLongTimeAM
- else
- ANumberFormat := nfShortTimeAM;
- end else begin
- if isLongTime then
- ANumberFormat := nfLongTime
- else
- ANumberFormat := nfShortTime;
- end;
- end;
+ end;
+
+var
+ lNumFormatData: TsNumFormatData;
+begin
+ lNumFormatData := FindNumFormatDataForCell(AXFIndex);
+ if lNumFormatData <> nil then begin
+ ANumberFormat := lNumFormatData.NumFormat;
+ ANumberFormatStr := lNumFormatData.FormatString;
+ ADecimals := lNumFormatData.Decimals;
+ FixMilliseconds;
+ end else begin
+ ANumberFormat := nfGeneral;
+ ANumberFormatStr := '';
+ ADecimals := 0;
end;
end;
{ Determines the format data (for numerical formatting) which belong to a given
- XF record.
- Does not return data for built-in formats. }
-function TsSpreadBIFFReader.FindFormatDataForCell(const AXFIndex: Integer
- ): TFormatListData;
+ XF record. }
+function TsSpreadBIFFReader.FindNumFormatDataForCell(const AXFIndex: Integer
+ ): TsNumFormatData;
var
lXFData: TXFListData;
i: Integer;
begin
- lXFData := TXFListData(FXFList.Items[AXFIndex]);
- for i := 0 to FFormatList.Count-1 do begin
- Result := TFormatListData(FFormatList.Items[i]);
- if Result.Index = lXFData.FormatIndex then Exit;
- end;
Result := nil;
+ lXFData := TXFListData(FXFList.Items[AXFIndex]);
+ i := NumFormatList.Find(lXFData.FormatIndex);
+ if i <> -1 then Result := NumFormatList[i];
end;
{ Convert the number to a date/time and return that if it is }
@@ -772,7 +803,7 @@ function TsSpreadBIFFReader.IsDateTime(Number: Double;
ANumberFormat: TsNumberFormat; var ADateTime: TDateTime): boolean;
begin
if ANumberFormat in [
- nfShortDateTime, nfFmtDateTime, nfShortDate,
+ nfShortDateTime, nfFmtDateTime, nfShortDate, nfLongDate,
nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM] then
begin
ADateTime := ConvertExcelDateTimeToDateTime(Number, FDateMode);
@@ -788,7 +819,7 @@ begin
end;
end;
-// In BIFF 8 it seams to always use the UTF-16 codepage
+// In BIFF8 it seams to always use the UTF-16 codepage
procedure TsSpreadBIFFReader.ReadCodePage(AStream: TStream);
var
lCodePage: Word;
@@ -892,6 +923,76 @@ begin
// to be overridden
end;
+{ Reads a FORMULA record, retrieves the RPN formula and puts the result in the
+ corresponding field. The formula is not recalculated here!
+ Valid for BIFF5 and BIFF8. }
+procedure TsSpreadBIFFReader.ReadFormula(AStream: TStream);
+var
+ ARow, ACol: Cardinal;
+ XF: WORD;
+ ResultFormula: Double;
+ Data: array [0..7] of BYTE;
+ Flags: WORD;
+ FormulaSize: BYTE;
+ i: Integer;
+ dt: TDateTime;
+ nf: TsNumberFormat;
+ nd: Word;
+ nfs: String;
+
+begin
+ { BIFF Record header }
+ { BIFF Record data }
+ { Index to XF Record }
+ ReadRowColXF(AStream, ARow, ACol, XF);
+
+ { Result of the formula in IEE 754 floating-point value }
+ AStream.ReadBuffer(Data, Sizeof(Data));
+
+ { Options flags }
+ Flags := WordLEtoN(AStream.ReadWord);
+
+ { Not used }
+ AStream.ReadDWord;
+
+ { Formula size }
+ FormulaSize := WordLEtoN(AStream.ReadWord);
+
+ { Formula data, output as debug info }
+{ Write('Formula Element: ');
+ for i := 1 to FormulaSize do
+ Write(IntToHex(AStream.ReadByte, 2) + ' ');
+ WriteLn('');}
+
+ //RPN data not used by now
+ AStream.Position := AStream.Position + FormulaSize;
+
+ if (Data[6] = $FF) and (Data[7] = $FF) then
+ case Data[0] of
+ 0: FWorksheet.WriteUTF8Text(ARow, ACol, '(String)');
+ 1: FWorksheet.WriteUTF8Text(ARow, ACol, '(Bool)');
+ 2: FWorksheet.WriteUTF8Text(ARow, ACol, '(ERROR)');
+ 3: FWorksheet.WriteUTF8Text(ARow, ACol, '(empty)');
+ end
+ else begin
+ if SizeOf(Double) <> 8 then
+ raise Exception.Create('Double is not 8 bytes');
+
+ // Result is a number or a date/time
+ Move(Data[0], ResultFormula, SizeOf(Data));
+
+ {Find out what cell type, set content type and value}
+ ExtractNumberFormat(XF, nf, nd, nfs);
+ if IsDateTime(ResultFormula, nf, dt) then
+ FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
+ else
+ FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd);
+ end;
+
+ {Add attributes}
+ ApplyCellFormatting(ARow, ACol, XF);
+end;
+
// Reads multiple blank cell records
// Valid for BIFF5 and BIFF8 (does not exist before)
procedure TsSpreadBIFFReader.ReadMulBlank(AStream: TStream);
@@ -1168,6 +1269,15 @@ begin
// "15" is the index of the last pre-defined xf record
end;
+{ Creates the correct version of the number format list. It is for BIFF file
+ formats.
+ Valid for BIFF5.BIFF8. Needs to be overridden for BIFF2. }
+procedure TsSpreadBIFFWriter.CreateNumFormatList;
+begin
+ FreeAndNil(FNumFormatList);
+ FNumFormatList := TsBIFFNumFormatList.Create;
+end;
+
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
AElementKind: TFEKind; out ASecondaryID: Word): Word;
const
@@ -1469,6 +1579,30 @@ begin
WriteNumber(AStream, ARow, ACol, ExcelDateSerial, ACell);
end;
+{ Writes a BIFF format record defined in AFormatData. AListIndex the index of
+ the formatdata in the format list (not the FormatIndex!).
+ Needs to be overridden by descendants. }
+procedure TsSpreadBIFFWriter.WriteFormat(AStream: TStream;
+ AFormatData: TsNumFormatData; AListIndex: Integer);
+begin
+ // needs to be overridden
+end;
+
+{ Writes all number formats to the stream. Saving starts at the item with the
+ FirstFormatIndexInFile. }
+procedure TsSpreadBIFFWriter.WriteFormats(AStream: TStream);
+var
+ i: Integer;
+begin
+ ListAllNumFormats;
+ i := NumFormatList.Find(NumFormatList.FirstFormatIndexInFile);
+ while i < NumFormatList.Count do begin
+ if NumFormatList[i] <> nil then
+ WriteFormat(AStream, NumFormatList[i], i);
+ inc(i);
+ end;
+end;
+
{ Writes a 64-bit floating point NUMBER record.
Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure.). }
procedure TsSpreadBIFFWriter.WriteNumber(AStream: TStream;
@@ -1806,204 +1940,5 @@ begin
AStream.WriteWord(WordToLE(lXFIndex));
end;
-
-{ Format checking procedures }
-
-{ This simple parsing procedure of the Excel format string checks for a fixed
- float format s, i.e. s can be '0', '0.00', '000', '0,000', and returns the
- number of decimals, i.e. number of zeros behind the decimal point }
-function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
-var
- i: Integer;
- p: Integer;
- decs: String;
-begin
- Decimals := 0;
-
- // Check if s is a valid format mask.
- try
- FormatFloat(s, 1.0);
- except
- on EConvertError do begin
- Result := false;
- exit;
- end;
- end;
-
- // If it is count the zeros - each one is a decimal.
- if s = '0' then
- Result := true
- else begin
- p := pos('.', s); // position of decimal point;
- if p = 0 then begin
- Result := false;
- end else begin
- Result := true;
- for i:= p+1 to Length(s) do
- if s[i] = '0' then begin
- inc(Decimals)
- end
- else
- exit; // ignore characters after the last 0
- end;
- end;
-end;
-
-{ This function checks whether the format string corresponds to a thousand
- separator format like "#,##0.000' and returns the number of fixed decimals
- (i.e. zeros after the decimal point) }
-function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
-var
- i, p: Integer;
-begin
- Decimals := 0;
-
- // Check if s is a valid format string
- try
- FormatFloat(s, 1.0);
- except
- on EConvertError do begin
- Result := false;
- exit;
- end;
- end;
-
- // If it is look for the thousand separator. If found count decimals.
- Result := (Pos(',', s) > 0);
- if Result then begin
- p := pos('.', s);
- if p > 0 then
- for i := p+1 to Length(s) do
- if s[i] = '0' then
- inc(Decimals)
- else
- exit; // ignore format characters after the last 0
- end;
-end;
-
-
-{ This function checks whether the format string corresponds to percent
- formatting and determines the number of decimals }
-function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
-var
- i, p: Integer;
-begin
- Decimals := 0;
- // The signature of the percent format is a percent sign at the end of the
- // format string.
- Result := (s <> '') and (s[Length(s)] = '%');
- if Result then begin
- // Check for a valid format string
- Delete(s, Length(s), 1);
- try
- FormatDateTime(s, 1.0);
- except
- on EConvertError do begin
- Result := false;
- exit;
- end;
- end;
- // Count decimals
- p := pos('.', s);
- if p > 0 then
- for i := p+1 to Length(s)-1 do
- if s[i] = '0' then
- inc(Decimals)
- else
- exit; // ignore characters after last 0
- end;
-end;
-
-{ This function checks whether the format string corresponds to exponential
- formatting and determines the number of decimals }
-function IsExpNumberFormat(s: String; out Decimals: Word): Boolean;
-var
- i, p, pe: Integer;
-begin
- Result := false;
- Decimals := 0;
-
- if SameText(s, 'General') then
- exit;
-
- // Check for a valid format string
- try
- FormatDateTime(s, 1.0);
- except
- on EConvertError do begin
- exit;
- end;
- end;
-
- // Count decimals
- pe := pos('e', lowercase(s));
- result := pe > 0;
- if Result then begin
- p := pos('.', s);
- if (p > 0) then begin
- if p < pe then
- for i:=1 to pe-1 do
- if s[i] = '0' then
- inc(Decimals)
- else
- exit; // ignore characters after last 0
- end;
- end;
-end;
-
-{ IsDateFormat checks if the format string s corresponds to a date format }
-function IsDateFormat(s: String): Boolean;
-begin
- // Day, month, year are separated by a slash
- Result := (pos('/', s) > 0);
- if Result then
- // Check validity of format string
- try
- FormatDateTime(s, now);
- except on EConvertError do
- Result := false;
- end;
-end;
-
-{ IsTimeFormat checks if the format string s is a time format. isLong is
- true if the string contains hours, minutes and seconds (two colons).
- isAMPM is true if the string contains "AM/PM", "A/P" or "AMPM".
- isMilliSec is true if the string ends with a "z". }
-function IsTimeFormat(s: String; out isLong, isAMPM, isMillisec: Boolean): Boolean;
-var
- p, i, count: Integer;
-begin
- // Time parts are separated by a colon
- p := pos(':', s);
- isLong := false;
- isAMPM := false;
- result := p > 0;
-
- if Result then begin
- count := 1;
- s := Uppercase(s);
-
- // If there are is a second colon s is a "long" time format
- for i:=p+1 to Length(s) do
- if s[i] = ':' then begin
- isLong := true;
- break;
- end;
-
- // Seek for "AM/PM" etc to detect that specific format
- isAMPM := (pos('AM/PM', s) > 0) or (pos('A/P', s) > 0) or (pos('AMPM', s) > 0);
-
- // Look for the "milliseconds" character z
- isMilliSec := (s[Length(s)] = 'Z');
-
- // Check validity of format string
- try
- FormatDateTime(s, now);
- except on EConvertError do
- Result := false;
- end;
- end;
-end;
-
end.