fpspreadsheet: Write currency format codes for BIFF5 and BIFF8 (incl. "red" for negatives and "-" for zero).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3053 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-05-17 15:13:08 +00:00
parent aa29744538
commit f638eb928a
10 changed files with 416 additions and 199 deletions

View File

@ -267,7 +267,29 @@ begin
MyWorksheet.WriteFontColor(r, 3, scGray);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
MyWorksheet.WriteFontColor(r, 4, scGray);
inc(r,2);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrency, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrency, 0, '$');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrency, 0, '$');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrency, 0, '$');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyRed, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyRed, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyDash, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyDash, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyDash, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyDash, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyDashRed, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyDashRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyDashRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyDashRed, 0, 'USD');
inc(r, 2);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)');
MyWorksheet.WriteNumber(r, 1, number);
MyWorksheet.WriteFontColor(r, 1, scGray);
@ -344,6 +366,7 @@ begin
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
MyWorksheet.WriteFontColor(r, 1, scGray);
inc(r);
// Set width of columns 0 to 3
MyWorksheet.WriteColWidth(0, 50);

View File

@ -273,7 +273,29 @@ begin
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,2);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrency, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrency, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrency, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrency, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyRed, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyRed, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyDash, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyDash, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyDash, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyDash, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyDashRed, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyDashRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyDashRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyDashRed, 0, 'USD');
inc(r, 2);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)');
MyWorksheet.WriteNumber(r, 1, number);
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0_);("$"#,##0)');

View File

@ -37,6 +37,8 @@ begin
MyWorkbook := TsWorkbook.Create;
MyWorkbook.SetDefaultFont('Calibri', 9);
MyWorkbook.UsePalette(@PALETTE_BIFF8, Length(PALETTE_BIFF8));
MyWorkbook.FormatSettings.CurrencyFormat := 2;
MyWorkbook.FormatSettings.NegCurrFormat := 14;
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet1);
MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines];
@ -247,7 +249,8 @@ begin
MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 3 decs');
MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
inc(r);
inc(r,2);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
@ -283,7 +286,29 @@ begin
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,2);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrency, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrency, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrency, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrency, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyRed, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyRed, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyDash, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyDash, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyDash, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyDash, 0, 'USD');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyDashRed, 0 decs');
MyWorksheet.WriteNumber(r, 1, number, nfCurrencyDashRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 2, -number, nfCurrencyDashRed, 0, 'USD');
MyWorksheet.WriteNumber(r, 3, 0.0, nfCurrencyDashRed, 0, 'USD');
inc(r,2);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "EUR "#,##0_);("EUR "#,##0)');
MyWorksheet.WriteDateTime(r, 1, number);
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"EUR "#,##0_);("EUR "#,##0)');

View File

@ -128,8 +128,8 @@
<UnitName Value="mainform"/>
<EditorIndex Value="1"/>
<WindowIndex Value="0"/>
<TopLine Value="628"/>
<CursorPos X="30" Y="639"/>
<TopLine Value="394"/>
<CursorPos X="40" Y="412"/>
<UsageCount Value="200"/>
<Bookmarks Count="1">
<Item0 X="3" Y="361" ID="1"/>
@ -140,20 +140,20 @@
<Unit2>
<Filename Value="..\..\fpspreadsheet.pas"/>
<UnitName Value="fpspreadsheet"/>
<EditorIndex Value="3"/>
<EditorIndex Value="4"/>
<WindowIndex Value="0"/>
<TopLine Value="2655"/>
<CursorPos X="3" Y="2680"/>
<TopLine Value="2748"/>
<CursorPos X="1" Y="2748"/>
<UsageCount Value="100"/>
<Loaded Value="True"/>
</Unit2>
<Unit3>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<UnitName Value="fpspreadsheetgrid"/>
<EditorIndex Value="2"/>
<EditorIndex Value="5"/>
<WindowIndex Value="0"/>
<TopLine Value="1774"/>
<CursorPos X="23" Y="1783"/>
<TopLine Value="636"/>
<CursorPos X="20" Y="647"/>
<UsageCount Value="100"/>
<Loaded Value="True"/>
</Unit3>
@ -231,11 +231,11 @@
<Unit13>
<Filename Value="..\..\fpsutils.pas"/>
<UnitName Value="fpsutils"/>
<EditorIndex Value="8"/>
<EditorIndex Value="2"/>
<WindowIndex Value="0"/>
<TopLine Value="37"/>
<CursorPos X="1" Y="21"/>
<UsageCount Value="53"/>
<TopLine Value="1206"/>
<CursorPos X="21" Y="1222"/>
<UsageCount Value="54"/>
<Loaded Value="True"/>
</Unit13>
<Unit14>
@ -264,10 +264,10 @@
<Filename Value="..\..\xlsbiff8.pas"/>
<UnitName Value="xlsbiff8"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="5"/>
<EditorIndex Value="3"/>
<WindowIndex Value="0"/>
<TopLine Value="1727"/>
<CursorPos X="1" Y="1744"/>
<TopLine Value="1920"/>
<CursorPos X="11" Y="1932"/>
<UsageCount Value="84"/>
<Loaded Value="True"/>
</Unit17>
@ -289,32 +289,26 @@
<Unit20>
<Filename Value="..\..\xlscommon.pas"/>
<UnitName Value="xlscommon"/>
<EditorIndex Value="4"/>
<WindowIndex Value="0"/>
<TopLine Value="974"/>
<CursorPos X="21" Y="990"/>
<TopLine Value="509"/>
<CursorPos X="68" Y="517"/>
<UsageCount Value="80"/>
<Loaded Value="True"/>
</Unit20>
<Unit21>
<Filename Value="..\..\xlsbiff5.pas"/>
<UnitName Value="xlsbiff5"/>
<EditorIndex Value="6"/>
<WindowIndex Value="0"/>
<TopLine Value="76"/>
<CursorPos X="49" Y="92"/>
<UsageCount Value="67"/>
<Loaded Value="True"/>
</Unit21>
<Unit22>
<Filename Value="..\..\xlsbiff2.pas"/>
<UnitName Value="xlsbiff2"/>
<EditorIndex Value="7"/>
<WindowIndex Value="0"/>
<TopLine Value="548"/>
<CursorPos X="1" Y="560"/>
<UsageCount Value="68"/>
<Loaded Value="True"/>
</Unit22>
<Unit23>
<Filename Value="d:\lazarus-svn\lcl\lclproc.pas"/>
@ -590,124 +584,124 @@
</Units>
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="mainform.pas"/>
<Caret Line="346" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1437" Column="1" TopLine="1407"/>
</Position1>
<Position2>
<Filename Value="mainform.pas"/>
<Caret Line="354" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1410" Column="1" TopLine="1403"/>
</Position2>
<Position3>
<Filename Value="mainform.pas"/>
<Caret Line="346" Column="8" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1411" Column="1" TopLine="1403"/>
</Position3>
<Position4>
<Filename Value="mainform.pas"/>
<Caret Line="343" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1412" Column="1" TopLine="1403"/>
</Position4>
<Position5>
<Filename Value="mainform.pas"/>
<Caret Line="346" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1414" Column="1" TopLine="1403"/>
</Position5>
<Position6>
<Filename Value="mainform.pas"/>
<Caret Line="347" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1416" Column="1" TopLine="1403"/>
</Position6>
<Position7>
<Filename Value="mainform.pas"/>
<Caret Line="348" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1417" Column="1" TopLine="1403"/>
</Position7>
<Position8>
<Filename Value="mainform.pas"/>
<Caret Line="349" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1423" Column="1" TopLine="1403"/>
</Position8>
<Position9>
<Filename Value="mainform.pas"/>
<Caret Line="350" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1437" Column="1" TopLine="1406"/>
</Position9>
<Position10>
<Filename Value="mainform.pas"/>
<Caret Line="351" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1929" Column="3" TopLine="1920"/>
</Position10>
<Position11>
<Filename Value="mainform.pas"/>
<Caret Line="354" Column="1" TopLine="336"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1567" Column="1" TopLine="1548"/>
</Position11>
<Position12>
<Filename Value="mainform.pas"/>
<Caret Line="640" Column="1" TopLine="621"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1934" Column="1" TopLine="1915"/>
</Position12>
<Position13>
<Filename Value="mainform.pas"/>
<Caret Line="641" Column="1" TopLine="621"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1937" Column="1" TopLine="1915"/>
</Position13>
<Position14>
<Filename Value="mainform.pas"/>
<Caret Line="343" Column="1" TopLine="324"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1940" Column="1" TopLine="1915"/>
</Position14>
<Position15>
<Filename Value="mainform.pas"/>
<Caret Line="632" Column="30" TopLine="621"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2761" Column="1" TopLine="2742"/>
</Position15>
<Position16>
<Filename Value="mainform.pas"/>
<Caret Line="633" Column="30" TopLine="622"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2762" Column="1" TopLine="2742"/>
</Position16>
<Position17>
<Filename Value="mainform.pas"/>
<Caret Line="634" Column="30" TopLine="623"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2763" Column="1" TopLine="2742"/>
</Position17>
<Position18>
<Filename Value="mainform.pas"/>
<Caret Line="635" Column="30" TopLine="624"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1925" Column="17" TopLine="1915"/>
</Position18>
<Position19>
<Filename Value="mainform.pas"/>
<Caret Line="636" Column="30" TopLine="625"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2765" Column="3" TopLine="2751"/>
</Position19>
<Position20>
<Filename Value="mainform.pas"/>
<Caret Line="637" Column="30" TopLine="626"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1567" Column="1" TopLine="1548"/>
</Position20>
<Position21>
<Filename Value="mainform.pas"/>
<Caret Line="638" Column="30" TopLine="627"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1934" Column="1" TopLine="1915"/>
</Position21>
<Position22>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="592" Column="61" TopLine="588"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1937" Column="1" TopLine="1915"/>
</Position22>
<Position23>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="89" Column="48" TopLine="62"/>
<Caret Line="1940" Column="1" TopLine="1915"/>
</Position23>
<Position24>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1751" Column="16" TopLine="1743"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2761" Column="1" TopLine="2751"/>
</Position24>
<Position25>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1237" Column="67" TopLine="1222"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2762" Column="1" TopLine="2751"/>
</Position25>
<Position26>
<Filename Value="..\..\xlsbiff2.pas"/>
<Caret Line="73" Column="48" TopLine="61"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2772" Column="1" TopLine="2751"/>
</Position26>
<Position27>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="89" Column="29" TopLine="73"/>
<Caret Line="1934" Column="1" TopLine="1915"/>
</Position27>
<Position28>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="365" Column="16" TopLine="353"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1937" Column="1" TopLine="1915"/>
</Position28>
<Position29>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="1379" Column="1" TopLine="1363"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1940" Column="1" TopLine="1915"/>
</Position29>
<Position30>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1754" Column="1" TopLine="1742"/>
<Caret Line="1439" Column="1" TopLine="1421"/>
</Position30>
</JumpHistory>
</ProjectOptions>
@ -739,7 +733,7 @@
<Debugging>
<Watches Count="2">
<Item1>
<Expression Value="acol"/>
<Expression Value="recordtype"/>
</Item1>
<Item2>
<Expression Value="arow"/>

View File

@ -410,7 +410,7 @@ begin
exit;
cell := Worksheet.FindCell(GetWorksheetRow(Row), GetWorksheetCol(Col));
if (cell <> nil) then begin
decs := cell^.NumberDecimals;
decs := cell^.Decimals;
if (Sender = AcIncDecimals) then
Worksheet.WriteDecimals(cell, decs+1);
if (Sender = AcDecDecimals) and (decs > 0) then

View File

@ -153,9 +153,18 @@ type
{@@ Number/cell formatting. Only uses a subset of the default formats,
enough to be able to read/write date/time values.
nfCustom allows to apply a format string directly. }
TsNumberFormat = (nfGeneral, nfFixed, nfFixedTh, nfExp, nfSci, nfPercentage,
TsNumberFormat = (
// general-purpose for all numbers
nfGeneral,
// numbers
nfFixed, nfFixedTh, nfExp, nfSci, nfPercentage,
// currency
nfCurrency, nfCurrencyRed, nfCurrencyDash, nfCurrencyDashRed,
// dates and times
nfShortDateTime, nfFmtDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
nfShortTimeAM, nfLongTimeAM, nfTimeInterval, nfCustom);
nfShortTimeAM, nfLongTimeAM, nfTimeInterval,
// other (format string goes directly into the file)
nfCustom);
{@@ Text rotation formatting. The text is rotated relative to the standard
orientation, which is from left to right horizontal:
@ -306,7 +315,8 @@ type
BackgroundColor: TsColor;
NumberFormat: TsNumberFormat;
NumberFormatStr: String;
NumberDecimals: Word;
Decimals: Byte;
CurrencySymbol: String;
RGBBackgroundColor: TFPColor; // only valid if BackgroundColor=scRGBCOLOR
end;
@ -383,7 +393,8 @@ type
{ Writing of values }
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
AFormat: TsNumberFormat = nfGeneral; ADecimals: Word = 2); overload;
AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2;
ACurrencySymbol: String = ''); overload;
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
AFormatString: String); overload;
procedure WriteBlank(ARow, ACol: Cardinal);
@ -459,6 +470,7 @@ type
{ Internal methods }
procedure RemoveWorksheetsCallback(data, arg: pointer);
public
FormatSettings: TFormatSettings;
{ Base methods }
constructor Create;
destructor Destroy; override;
@ -514,7 +526,8 @@ type
public
Index: Integer;
NumFormat: TsNumberFormat;
Decimals: Integer;
Decimals: Byte;
CurrencySymbol: String;
FormatString: string;
end;
@ -529,20 +542,22 @@ type
FNextFormatIndex: Integer;
procedure AddBuiltinFormats; virtual;
procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
var ANumFormat: TsNumberFormat; var ADecimals: Word); virtual;
var ANumFormat: TsNumberFormat; var ADecimals: byte;
var ACurrencySymbol: String); 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;
AFormatString: String = ''; ADecimals: Byte = 0;
ACurrencySymbol: String = ''): 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;
ADecimals: Byte; ACurrencySymbol: String): Integer; overload;
function Find(AFormatIndex: Integer): Integer; overload;
function FormatStringForWriting(AIndex: Integer): String; virtual;
procedure Sort;
@ -976,7 +991,8 @@ begin
cell^.TextRotation := AFormat^.TextRotation;
cell^.NumberFormat := AFormat^.NumberFormat;
cell^.NumberFormatStr := AFormat^.NumberFormatStr;
cell^.NumberDecimals := AFormat^.NumberDecimals;
cell^.Decimals := AFormat^.Decimals;
cell^.CurrencySymbol := AFormat^.CurrencySymbol;
ChangedCell(AToRow, AToCol);
ChangedFont(AToRow, AToCol);
@ -1190,8 +1206,11 @@ end;
function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
function FloatToStrNoNaN(const Value: Double;
ANumberFormat: TsNumberFormat; ANumberFormatStr: string; ADecimals: Word): ansistring;
ANumberFormat: TsNumberFormat; ANumberFormatStr: string; ADecimals: byte): ansistring;
var
fs: TFormatSettings;
begin
fs := FWorkbook.FormatSettings;
if IsNan(Value) then
Result := ''
else
@ -1199,12 +1218,12 @@ function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
Result := SciFloat(Value, ADecimals)
else
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
Result := FloatToStr(Value)
Result := FloatToStr(Value, fs)
else
if (ANumberFormat = nfPercentage) then
Result := FormatFloat(ANumberFormatStr, Value*100) // '%' is already added to FormatStr.
Result := FormatFloat(ANumberFormatStr, Value*100, fs)
else
Result := FormatFloat(ANumberFormatStr, Value);
Result := FormatFloat(ANumberFormatStr, Value, fs)
end;
function DateTimeToStrNoNaN(const Value: Double;
@ -1212,15 +1231,10 @@ function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
begin
Result := '';
if not IsNaN(Value) then begin
(*
if ANumberFormat = nfTimeInterval then
Result := TimeIntervalToString(Value, ANumberFormatStr)
else
*)
if ANumberFormatStr = '' then
Result := FormatDateTime('c', Value)
else
Result := FormatDateTime(ANumberFormatStr, Value);
Result := FormatDateTimeEx(ANumberFormatStr, Value);
end;
end;
@ -1238,11 +1252,11 @@ begin
with ACell^ do
case ContentType of
cctNumber:
Result := FloatToStrNoNaN(NumberValue, NumberFormat, NumberFormatStr, NumberDecimals);
Result := FloatToStrNoNaN(NumberValue, NumberFormat, NumberFormatStr, Decimals);
cctUTF8String:
Result := UTF8StringValue;
cctDateTime:
Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr, NumberDecimals);
Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr, Decimals);
cctBool:
Result := IfThen(BoolValue, lpTRUE, lpFALSE);
cctError:
@ -1265,33 +1279,15 @@ var
ACell: PCell;
Str: string;
begin
Result := 0.0;
ACell := FindCell(ARow, ACol);
if ACell = nil then
begin
Result := 0.0;
Exit;
end;
exit;
case ACell^.ContentType of
//cctFormula
cctDateTime : Result := ACell^.DateTimeValue; //this is in FPC TDateTime format, not Excel
cctNumber : Result := ACell^.NumberValue;
cctUTF8String:
begin
// The try is necessary to catch errors while converting the string
// to a number, an operation which may fail
try
Str := ACell^.UTF8StringValue;
Result := StrToFloat(Str);
except
Result := 0.0;
end;
end;
else
Result := 0.0;
cctDateTime : Result := ACell^.DateTimeValue; //this is in FPC TDateTime format, not Excel
cctNumber : Result := ACell^.NumberValue;
cctUTF8String : TryStrToFloat(ACell^.UTF8StringValue, Result);
end;
end;
@ -1395,21 +1391,27 @@ end;
@param ANumber The number to be written
@param AFormat The format identifier, e.g. nfFixed (optional)
@param ADecimals The number of decimals used for formatting (optional)
@param ACurrencySymbol The currency symbol in case of currency format (nfCurrency)
}
procedure TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: double;
AFormat: TsNumberFormat = nfGeneral; ADecimals: Word = 2);
AFormat: TsNumberFormat = nfGeneral; ADecimals: Byte = 2;
ACurrencySymbol: String = '');
var
ACell: PCell;
fs: TFormatSettings;
begin
ACell := GetCell(ARow, ACol);
ACell^.ContentType := cctNumber;
ACell^.NumberValue := ANumber;
ACell^.NumberDecimals := ADecimals;
ACell^.Decimals := ADecimals;
if AFormat <> nfGeneral then begin
Include(ACell^.UsedFormattingFields, uffNumberFormat);
ACell^.NumberFormat := AFormat;
WriteDecimals(ACell, ADecimals);
ACell^.Decimals := ADecimals;
ACell^.CurrencySymbol := ACurrencySymbol;
ACell^.NumberFormatStr := BuildNumFormatString(ACell^.NumberFormat,
Workbook.FormatSettings, ADecimals, ACurrencySymbol);
end;
ChangedCell(ARow, ACol);
end;
@ -1539,8 +1541,9 @@ end;
procedure TsWorksheet.WriteDecimals(ACell: PCell; ADecimals: Byte);
begin
if (ACell <> nil) and (ACell^.ContentType = cctNumber) then begin
ACell^.NumberDecimals := ADecimals;
ACell^.NumberFormatStr := BuildNumFormatString(ACell^.NumberFormat, ADecimals);
ACell^.Decimals := ADecimals;
ACell^.NumberFormatStr := BuildNumFormatString(ACell^.NumberFormat,
FWorkbook.FormatSettings, ADecimals, ACell^.CurrencySymbol);
ChangedCell(ACell^.Row, ACell^.Col);
end;
end;
@ -1598,7 +1601,8 @@ begin
Include(ACell^.UsedFormattingFields, uffNumberFormat);
ACell^.NumberFormat := ANumberFormat;
if (AFormatString = '') then
ACell^.NumberFormatStr := BuildNumFormatString(ANumberFormat, ACell^.NumberDecimals)
ACell^.NumberFormatStr := BuildNumFormatString(ANumberFormat,
Workbook.FormatSettings, ACell^.Decimals, ACell^.CurrencySymbol)
else
ACell^.NumberFormatStr := AFormatString;
ChangedCell(ARow, ACol);
@ -1966,6 +1970,7 @@ constructor TsWorkbook.Create;
begin
inherited Create;
FWorksheets := TFPList.Create;
FormatSettings := DefaultFormatSettings;
FFontList := TFPList.Create;
SetDefaultFont('Arial', 10.0);
InitFonts;
@ -2585,7 +2590,7 @@ 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;
AFormatString: String = ''; ADecimals: byte = 0; ACurrencySymbol: String = ''): integer;
var
item: TsNumFormatData;
begin
@ -2594,6 +2599,7 @@ begin
item.NumFormat := ANumFormat;
item.FormatString := AFormatString;
item.Decimals := ADecimals;
item.CurrencySymbol := ACurrencySymbol;
Result := inherited Add(item);
end;
@ -2607,8 +2613,12 @@ begin
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);
Result := AddFormat(FNextFormatIndex,
AFormatCell^.NumberFormat,
AFormatCell^.NumberFormatStr,
AFormatCell^.Decimals,
AFormatCell^.CurrencySymbol
);
inc(FNextFormatIndex);
end;
@ -2634,7 +2644,7 @@ end;
about the structure of the string in the actual file format. }
procedure TsCustomNumFormatList.Analyze(AFormatIndex: Integer;
var AFormatString: String; var ANumFormat: TsNumberFormat;
var ADecimals: Word);
var ADecimals: Byte; var ACurrencySymbol: String);
const
SHORT_LONG_DATE: array[boolean] of TsNumberFormat = (
nfShortDate, nfLongDate
@ -2646,6 +2656,10 @@ const
EXP_SCI: array[boolean] of TsNumberFormat = (
nfExp, nfSci
);
CURR_FMT: array[boolean, boolean] of TsNumberFormat = (
(nfCurrency, nfCurrencyDash),
(nfCurrencyRed, nfCurrencyDashRed)
);
var
decs: Word;
isAMPM: Boolean;
@ -2654,6 +2668,7 @@ var
isInterval: Boolean;
isSci: Boolean;
isTime, isDate: Boolean;
isCurrRed, isCurrDash: Boolean;
lFormatData: TsNumFormatData;
i: Integer;
fmt: String;
@ -2685,6 +2700,13 @@ begin
IsTimeFormat(AFormatString, isLongTime, isAMPM, isInterval, ADecimals);
exit;
end;
nfCurrency, nfCurrencyRed, nfCurrencyDash, nfCurrencyDashRed:
begin
ANumFormat := lFormatData.NumFormat;
AFormatString := lFormatData.FormatString;
ADecimals := lFormatData.Decimals;
ACurrencySymbol := lFormatData.CurrencySymbol;
end;
end;
end;
@ -2702,6 +2724,9 @@ begin
else
if IsFixedNumberFormat(AFormatString, ADecimals) then
ANumFormat := nfFixed
else
if IsCurrencyFormat(AFormatString, ADecimals, ACurrencySymbol, isCurrRed, isCurrDash) then
ANumFormat := CURR_FMT[isCurrRed, isCurrDash]
else begin
isTime := IsTimeFormat(AFormatString, isLongTime, isAMPM, isInterval, ADecimals);
isDate := IsDateFormat(AFormatString, isLongDate);
@ -2731,16 +2756,17 @@ procedure TsCustomNumFormatList.AnalyzeAndAdd(AFormatIndex: Integer;
AFormatString: String);
var
nf: TsNumberFormat;
decs: Word;
decs: Byte;
currsym: String;
begin
if Find(AFormatIndex) > -1 then
raise Exception.Create('TsCustomNumFormatList.AnalyzeAndAdd: Format index must be unique.');
exit;
// Analyze the format string and extract information for internal formatting
Analyze(AFormatIndex, AFormatString, nf, decs);
Analyze(AFormatIndex, AFormatString, nf, decs, currsym);
// Add the new item
AddFormat(AFormatIndex, nf, AFormatString, decs);
AddFormat(AFormatIndex, nf, AFormatString, decs, currSym);
end;
{ Clears the list and frees memory occupied by the format items. }
@ -2767,13 +2793,14 @@ begin
if AFormatCell = nil then
Result := -1
else
Result := Find(AFormatCell^.NumberFormat, AFormatCell^.NumberFormatStr, AFormatCell^.NumberDecimals);
Result := Find(AFormatCell^.NumberFormat, AFormatCell^.NumberFormatStr,
AFormatCell^.Decimals, AFormatCell^.CurrencySymbol);
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;
AFormatString: String; ADecimals: Byte; ACurrencySymbol: String): Integer;
var
item: TsNumFormatData;
fmt: String;
@ -2837,6 +2864,8 @@ begin
and (item.NumFormat = ANumFormat)
and (item.FormatString = AFormatString)
and (item.Decimals = ADecimals)
and (not (item.NumFormat in [nfCurrency, nfCurrencyRed, nfCurrencyDash, nfCurrencyDashRed])
or (item.CurrencySymbol = ACurrencySymbol))
then
exit;
end;
@ -3037,7 +3066,12 @@ begin
if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue;
case AFormat^.NumberFormat of
nfFixed, nfFixedTh, nfPercentage, nfExp, nfSci:
if (FFormattingStyles[i].NumberDecimals <> AFormat^.NumberDecimals) then Continue;
if (FFormattingStyles[i].Decimals <> AFormat^.Decimals) then Continue;
nfCurrency, nfCurrencyRed, nfCurrencyDash, nfCurrencyDashRed:
begin
if (FFormattingStyles[i].Decimals <> AFormat^.Decimals) then Continue;
if (FFormattingStyles[i].CurrencySymbol <> AFormat^.CurrencySymbol) then Continue;
end;
nfShortDate, nfLongDate, nfShortDateTime, nfShortTime, nfLongTime,
nfShortTimeAM, nfLongTimeAM, nfFmtDateTime, nfTimeInterval, nfCustom:
if (FFormattingstyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue;
@ -3058,11 +3092,11 @@ end;
procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
var
isLong, isAMPM, isInterval: Boolean;
decs: Word;
decs: Byte;
begin
if ACell^.NumberFormat = nfFmtDateTime then begin
if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
ACell^.NumberDecimals := decs;
ACell^.Decimals := decs;
end;
end;

View File

@ -665,6 +665,10 @@ begin
Canvas.Font.Size := round(fnt.Size);
end;
end;
if (lCell^.NumberFormat in [nfCurrencyRed, nfCurrencyDashRed]) and
not IsNaN(lCell^.NumberValue) and (lCell^.NumberValue < 0)
then
Canvas.Font.Color := FWorkbook.GetPaletteColor(scRed);
// Wordwrap, text alignment and text rotation are handled by "DrawTextInCell".
end;
end;

View File

@ -60,21 +60,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 IsCurrencyFormat(s: String; out Decimals: Byte; out CurrSymbol: String;
out IsCurrencyRedFmt, IsCurrencyDashFmt: Boolean): Boolean;
function IsExpNumberFormat(s: String; out Decimals: Byte; out IsSci: Boolean): Boolean;
function IsFixedNumberFormat(s: String; out Decimals: Byte): Boolean;
function IsPercentNumberFormat(s: String; out Decimals: Byte): Boolean;
function IsThousandSepNumberFormat(s: String; out Decimals: Byte): Boolean;
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
function IsTimeFormat(s: String; out isLong, isAMPM, isInterval: Boolean;
out SecDecimals: Word): Boolean;
out SecDecimals: Byte): Boolean;
function BuildNumFormatString(ANumberFormat: TsNumberFormat; ADecimals: Byte): String;
function BuildNumFormatString(ANumberFormat: TsNumberFormat;
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
ACurrencySymbol: String = '?'): String;
function SciFloat(AValue: Double; ADecimals: Word): String;
function SciFloat(AValue: Double; ADecimals: Byte): String;
//function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
function FormatDateTime(const FormatStr: string; DateTime: TDateTime): string;
function FormatDateTimeEx(const FormatStr: string; DateTime: TDateTime): string;
implementation
@ -493,7 +497,7 @@ end;
{ 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;
function IsFixedNumberFormat(s: String; out Decimals: Byte): Boolean;
var
i: Integer;
p: Integer;
@ -540,7 +544,7 @@ 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;
function IsThousandSepNumberFormat(s: String; out Decimals: Byte): Boolean;
var
i, p: Integer;
begin
@ -571,7 +575,7 @@ 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;
function IsPercentNumberFormat(s: String; out Decimals: Byte): Boolean;
var
i, p: Integer;
begin
@ -600,11 +604,18 @@ begin
end;
end;
{ This function checks whether the format string corresponds to a currency format. }
function IsCurrencyFormat(s: String; out Decimals: Byte; out CurrSymbol: String;
out IsCurrencyRedFmt, IsCurrencyDashFmt: Boolean): Boolean;
begin
Result := false; // TO DO !!!!
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;
function IsExpNumberFormat(s: String; out Decimals: Byte;
out IsSci: Boolean): Boolean;
var
i, pdp, pe, ph: Integer;
@ -674,7 +685,7 @@ end;
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;
out SecDecimals: Byte): Boolean;
var
p, pdp, i, count: Integer;
begin
@ -734,10 +745,41 @@ end;
{ Builds a number format string from the numberformat code and the count of
decimals. }
function BuildNumFormatString(ANumberFormat: TsNumberFormat;
ADecimals: Byte): String;
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
ACurrencySymbol: String = '?'): String;
const
POS_FMT: array[0..3] of string = ( //0: value, 1: currency symbol
'"%1:s"%0:s',
'%0:s"%1:s"',
'"%1:s" %0:s',
'%0:s "%1:s"'
);
NEG_FMT: array[0..15] of string = (
'("%1:s"%0:s)', // 0
'-"%1:s"%0:s', // 1
'"%1:s"-%0:s', // 2
'"%1:s"%0:s-', // 3
'(%0:s"%1:s")', // 4
'-%0:s"%1:s"', // 5
'-%0:s-"%1:s"', // 6
'%0:s"%1:s"-', // 7
'-%0:s "%1:s"', // 8
'-"%1:s" %0:s', // 9
'%0:s "%1:s"-', // 10
'"%1:s" %0:s-', // 11
'"%1:s" -%0:s', // 12
'%0:s- "%1:s"', // 13
'("%1:s" %0:s)', // 14
'(%0:s "%1:s")' // 15
);
var
decs: String;
cf, ncf: Byte;
begin
cf := AFormatSettings.CurrencyFormat;
ncf := AFormatSettings.NegCurrFormat;
if ADecimals = -1 then ADecimals := AFormatSettings.CurrencyDecimals;
if ACurrencySymbol = '?' then ACurrencySymbol := AFormatSettings.CurrencyString;
decs := DupeString('0', ADecimals);
if ADecimals > 0 then decs := '.' + decs;
case ANumberFormat of
@ -751,15 +793,39 @@ begin
Result := '##0' + decs + 'E+0';
nfPercentage:
Result := '0' + decs + '%';
else
Result := '';
nfCurrency,
nfCurrencyRed,
nfCurrencyDash,
nfCurrencyDashRed:
begin
Result := '';
if ACurrencySymbol <> '' then
Result := Format(POS_FMT[cf], ['#,##0' + decs, ACurrencySymbol]) + ';'
+ Format(NEG_FMT[ncf], ['#,##0' + decs, ACurrencySymbol])
else begin
Result := '#,##0' + decs;
case ncf of
0, 14, 15 : Result := Result + ';(#,##0' + decs + ')';
1, 5, 6, 8, 9, 12: Result := Result + ';-#,##0' + decs;
else Result := Result + ';#,##0' + decs + '-';
end;
end;
if ANumberFormat in [nfCurrency, nfCurrencyRed] then begin
Result := Result + ';0' + decs;
if cf in [2,3] then
Result := Format('%s "%s"', [Result, ACurrencySymbol])
else
Result := Format('%s"%s"', [Result, ACurrencySymbol]);
end else
Result := Result + ';-';
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;
function SciFloat(AValue: Double; ADecimals: Byte): String;
var
m: Double;
ex: Integer;
@ -1177,7 +1243,7 @@ begin
result := StrPas(@ResultBuffer[0]);
end ;
function FormatDateTime(const FormatStr: string; DateTime: TDateTime): string;
function FormatDateTimeEx(const FormatStr: string; DateTime: TDateTime): string;
begin
DateTimeToString(Result, FormatStr, DateTime, DefaultFormatSettings);
end;

View File

@ -58,8 +58,8 @@ type
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;
out ANumberFormat: TsNumberFormat; out ADecimals: Byte;
out ACurrencySymbol: String; out ANumberFormatStr: String); override;
procedure ReadBlank(AStream: TStream); override;
procedure ReadColWidth(AStream: TStream);
procedure ReadFont(AStream: TStream);
@ -289,8 +289,8 @@ 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;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String);
out ANumberFormat: TsNumberFormat; out ADecimals: Byte;
out ACurrencySymbol: String; out ANumberFormatStr: String);
var
lNumFormatData: TsNumFormatData;
begin
@ -299,10 +299,12 @@ begin
ANumberFormat := lNumFormatData.NumFormat;
ANumberFormatStr := lNumFormatData.FormatString;
ADecimals := lNumFormatData.Decimals;
ACurrencySymbol := lNumFormatData.CurrencySymbol;
end else begin
ANumberFormat := nfGeneral;
ANumberFormatStr := '';
ADecimals := 0;
ACurrencySymbol := '';
end;
end;
@ -470,7 +472,8 @@ var
value: Double;
dt: TDateTime;
nf: TsNumberFormat;
nd: Word;
nd: Byte;
ncs: String;
nfs: String;
begin
{ BIFF Record row/column/style }
@ -480,11 +483,11 @@ begin
AStream.ReadBuffer(value, 8);
{Find out what cell type, set content type and value}
ExtractNumberFormat(XF, nf, nd, nfs);
ExtractNumberFormat(XF, nf, nd, ncs, nfs);
if IsDateTime(value, nf, dt) then
FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, value, nf, nd);
FWorksheet.WriteNumber(ARow, ACol, value, nf, nd, ncs);
{ Apply formatting to cell }
ApplyCellFormatting(ARow, ACol, XF);
@ -723,15 +726,17 @@ var
begin
case ACell.NumberFormat of
nfExp:
if ACell.NumberDecimals <> 2 then begin
ACell.NumberDecimals := 2;
if ACell.Decimals <> 2 then begin
ACell.Decimals := 2;
ACell.CurrencySymbol := '';
ACell.NumberFormatStr := '0.00E+00';
end;
nfSci:
begin
ACell.NumberFormat := nfExp;
ACell.NumberFormatStr := '0.00E+00';
ACell.NumberDecimals := 2;
ACell.Decimals := 2;
ACell.CurrencySymbol := '';
end;
nfFmtDateTime:
begin

View File

@ -349,7 +349,8 @@ type
protected
procedure AddBuiltinFormats; override;
procedure Analyze(AFormatIndex: Integer; var AFormatString: String;
var ANumFormat: TsNumberFormat; var ADecimals: Word); override;
var ANumFormat: TsNumberFormat; var ADecimals: Byte;
var ACurrencySymbol: String); override;
public
function FormatStringForWriting(AIndex: Integer): String; override;
end;
@ -369,8 +370,8 @@ type
function DecodeRKValue(const ARK: DWORD): Double;
// Returns the numberformat for a given XF record
procedure ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String); virtual;
out ANumberFormat: TsNumberFormat; out ADecimals: Byte;
out ACurrencySymbol: String; out ANumberFormatStr: String); virtual;
// Finds format record for XF record pointed to by cell
// Will not return info for built-in formats
function FindNumFormatDataForCell(const AXFIndex: Integer): TsNumFormatData;
@ -532,19 +533,41 @@ begin
end;
{ TsBIFFNumFormatParser } (*
constructor TsBIFFNumFormatParser.Create(AFormatString: String);
begin
inherited;
FFormatString := AFormatString;
Parse;
end;
procedure TsBIFFNumFormatParser.Parse;
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;
var
cs: String;
begin
cs := DefaultFormatSettings.CurrencyString;
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( 5, nfCurrency, '', 0);
AddFormat( 6, nfCurrencyRed, '', 0); // negative numbers in red
AddFormat( 7, nfCurrency, '', 2);
AddFormat( 8, nfCurrencyRed, '', 2);
AddFormat( 9, nfPercentage, '0%', 0);
AddFormat(10, nfPercentage, '0.00%', 2);
AddFormat(11, nfExp, '0.00E+00', 2);
@ -558,10 +581,18 @@ begin
AddFormat(20, nfShortTime);
AddFormat(21, nfLongTime);
AddFormat(22, nfShortDateTime);
// 23..44 not supported
// 23..36 not supported
AddFormat(37, nfCurrency, '', 0);
AddFormat(38, nfCurrencyRed, '', 0);
AddFormat(39, nfCurrency, '', 2);
AddFormat(40, nfCurrencyRed, '', 2);
AddFormat(41, nfCurrencyDash, '', 0);
AddFormat(42, nfCurrencyDashRed, '', 0);
AddFormat(43, nfCurrencyDash, '', 2);
AddFormat(44, nfCurrencyDashRed, '', 2);
AddFormat(45, nfFmtDateTime, 'nn:ss');
AddFormat(46, nfTimeInterval, '[h]:nn:ss');
AddFormat(47, nfFmtDateTime, 'nn:ss.z'); // z will be replace by 0 later
AddFormat(47, nfFmtDateTime, 'nn:ss.z'); // z will be replaced by 0 later
AddFormat(48, nfSci, '##0.0E+00', 1);
// 49 ("Text") not supported
@ -575,7 +606,7 @@ end;
The output values will be passed to fpc. }
procedure TsBIFFNumFormatList.Analyze(AFormatIndex: Integer;
var AFormatString: String; var ANumFormat: TsNumberFormat;
var ADecimals: Word);
var ADecimals: Byte; var ACurrencySymbol: String);
var
fmt: String;
begin
@ -612,12 +643,14 @@ begin
ANumFormat := nfShortTime;
AFormatString := '';
end;
ADecimals := 0;
exit;
end;
ADecimals := 0;
exit;
// TO DO: Analyze currency
end;
inherited Analyze(AFormatIndex, AFormatString, ANumFormat, ADecimals);
inherited Analyze(AFormatIndex, AFormatString, ANumFormat, ADecimals, ACurrencySymbol);
end;
{ Creates formatting strings that are written into the file. }
@ -644,6 +677,11 @@ begin
// if added by user.
// We check here for safety and add the brackets if not there.
MakeTimeIntervalMask(item.FormatString, Result);
nfCurrencyRed, nfCurrencyDashRed:
begin
i := Pos(';', item.FormatString);
Result := Copy(item.FormatString, 1, i) + '[RED]'+ Copy(item.FormatString, i+1, Length(item.FormatString));
end;
end;
end;
@ -763,13 +801,13 @@ end;
{ Extracts number format data from an XF record index by AXFIndex.
Valid for BIFF5-BIFF8. Needs to be overridden for BIFF2 }
procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String);
out ANumberFormat: TsNumberFormat; out ADecimals: Byte;
out ACurrencySymbol: String; out ANumberFormatStr: String);
procedure FixMilliseconds;
var
isLong, isAMPM, isInterval: Boolean;
decs: Word;
decs: Byte;
i: Integer;
begin
if IsTimeFormat(ANumberFormatStr, isLong, isAMPM, isInterval, decs)
@ -790,11 +828,13 @@ begin
ANumberFormat := lNumFormatData.NumFormat;
ANumberFormatStr := lNumFormatData.FormatString;
ADecimals := lNumFormatData.Decimals;
ACurrencySymbol := lNumFormatData.CurrencySymbol;
FixMilliseconds;
end else begin
ANumberFormat := nfGeneral;
ANumberFormatStr := '';
ADecimals := 0;
ACurrencySymbol := '';
end;
end;
@ -951,7 +991,8 @@ var
i: Integer;
dt: TDateTime;
nf: TsNumberFormat;
nd: Word;
nd: Byte;
ncs: String;
nfs: String;
resultStr: String;
err: TErrorValue;
@ -1014,11 +1055,11 @@ begin
Move(Data[0], ResultFormula, SizeOf(Data));
{Find out what cell type, set content type and value}
ExtractNumberFormat(XF, nf, nd, nfs);
ExtractNumberFormat(XF, nf, nd, ncs, nfs);
if IsDateTime(ResultFormula, nf, dt) then
FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd);
FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd, ncs);
end;
{Add attributes}
@ -1061,8 +1102,9 @@ var
pending: integer;
RK: DWORD;
nf: TsNumberFormat;
nd: word;
nd: Byte;
nfs: String;
ncs: String;
begin
ARow := WordLEtoN(AStream.ReadWord);
fc := WordLEtoN(AStream.ReadWord);
@ -1072,11 +1114,11 @@ begin
RK := DWordLEtoN(AStream.ReadDWord);
lNumber := DecodeRKValue(RK);
{Find out what cell type, set contenttype and value}
ExtractNumberFormat(XF, nf, nd, nfs);
ExtractNumberFormat(XF, nf, nd, ncs, nfs);
if IsDateTime(lNumber, nf, lDateTime) then
FWorksheet.WriteDateTime(ARow, fc, lDateTime, nf, nfs)
else
FWorksheet.WriteNumber(ARow, fc, lNumber, nf, nd);
FWorksheet.WriteNumber(ARow, fc, lNumber, nf, nd, ncs);
inc(fc);
dec(pending, SizeOf(XF) + SizeOf(RK));
end;
@ -1098,8 +1140,9 @@ var
value: Double;
dt: TDateTime;
nf: TsNumberFormat;
nd: word;
nd: Byte;
nfs: String;
ncs: String;
begin
ReadRowColXF(AStream, ARow, ACol, XF);
@ -1107,11 +1150,11 @@ begin
AStream.ReadBuffer(value, 8);
{Find out what cell type, set content type and value}
ExtractNumberFormat(XF, nf, nd, nfs);
ExtractNumberFormat(XF, nf, nd, ncs, nfs);
if IsDateTime(value, nf, dt) then
FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, value, nf, nd);
FWorksheet.WriteNumber(ARow, ACol, value, nf, nd, ncs);
{ Add attributes to cell }
ApplyCellFormatting(ARow, ACol, XF);
@ -1178,7 +1221,8 @@ var
lDateTime: TDateTime;
Number: Double;
nf: TsNumberFormat; // Number format
nd: Word; // decimals
nd: Byte; // decimals
ncs: String; // Currency symbol
nfs: String; // Number format string
begin
{Retrieve XF record, row and column}
@ -1191,11 +1235,11 @@ begin
Number := DecodeRKValue(RK);
{Find out what cell type, set contenttype and value}
ExtractNumberFormat(XF, nf, nd, nfs);
ExtractNumberFormat(XF, nf, nd, ncs, nfs);
if IsDateTime(Number, nf, lDateTime) then
FWorksheet.WriteDateTime(ARow, ACol, lDateTime, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, Number, nf);
FWorksheet.WriteNumber(ARow, ACol, Number, nf, nd, ncs);
{Add attributes}
ApplyCellFormatting(ARow, ACol, XF);