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.