You've already forked lazarus-ccr
fpspreadsheet: Allow number formats with no leading digits. Add corresponding unit test cases.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6218 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -132,6 +132,8 @@ type
|
|||||||
NumFormat: TsNumberFormat;
|
NumFormat: TsNumberFormat;
|
||||||
{@@ Number of decimal places used by the format string }
|
{@@ Number of decimal places used by the format string }
|
||||||
Decimals: Byte;
|
Decimals: Byte;
|
||||||
|
{@@ Minimum number of digits before the decimal separator }
|
||||||
|
MinIntDigits: Byte;
|
||||||
{@@ Factor by which a number will be multiplied before converting to string }
|
{@@ Factor by which a number will be multiplied before converting to string }
|
||||||
Factor: Double;
|
Factor: Double;
|
||||||
{@@ Digits to be used for the integer part of a fraction }
|
{@@ Digits to be used for the integer part of a fraction }
|
||||||
@@ -310,7 +312,8 @@ function BuildDateTimeFormatString(ANumberFormat: TsNumberFormat;
|
|||||||
function BuildFractionFormatString(AMixedFraction: Boolean;
|
function BuildFractionFormatString(AMixedFraction: Boolean;
|
||||||
ANumeratorDigits, ADenominatorDigits: Integer): String;
|
ANumeratorDigits, ADenominatorDigits: Integer): String;
|
||||||
function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
|
function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
|
||||||
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1): String;
|
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
|
||||||
|
AMinIntDigits: Integer = 1): String;
|
||||||
|
|
||||||
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
|
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
|
||||||
|
|
||||||
@@ -1401,39 +1404,53 @@ end;
|
|||||||
value of the FormatSettings is used. In case of a
|
value of the FormatSettings is used. In case of a
|
||||||
fraction format "ADecimals" refers to the maximum count
|
fraction format "ADecimals" refers to the maximum count
|
||||||
digits of the denominator.
|
digits of the denominator.
|
||||||
|
@param AMinIntDigits minimum count of integer digits, i.e. count of '0' in
|
||||||
|
the format string before the decimal separator
|
||||||
|
|
||||||
@return String of formatting codes
|
@return String of formatting codes
|
||||||
|
|
||||||
@example ANumberFormat = nfFixedTh, ADecimals = 2 --> '#,##0.00'
|
@example ANumberFormat = nfFixedTh, ADecimals = 2 --> '#,##0.00'
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
|
function BuildNumberFormatString(ANumberFormat: TsNumberFormat;
|
||||||
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1): String;
|
const AFormatSettings: TFormatSettings; ADecimals: Integer = -1;
|
||||||
|
AMinIntDigits: Integer = 1): String;
|
||||||
var
|
var
|
||||||
decs: String;
|
decdigits: String;
|
||||||
|
intdigits: String;
|
||||||
begin
|
begin
|
||||||
Result := '';
|
Result := '';
|
||||||
|
if AMinIntDigits > 0 then
|
||||||
|
intdigits := DupeString('0', AMinIntDigits)
|
||||||
|
else
|
||||||
|
intdigits := '#';
|
||||||
if ADecimals = -1 then
|
if ADecimals = -1 then
|
||||||
ADecimals := AFormatSettings.CurrencyDecimals;
|
ADecimals := AFormatSettings.CurrencyDecimals;
|
||||||
decs := DupeString('0', ADecimals);
|
if ADecimals > 0 then
|
||||||
if ADecimals > 0 then decs := '.' + decs;
|
decdigits := '.' + DupeString('0', ADecimals)
|
||||||
|
else
|
||||||
|
decdigits := '';
|
||||||
case ANumberFormat of
|
case ANumberFormat of
|
||||||
nfText:
|
nfText:
|
||||||
Result := '@';
|
Result := '@';
|
||||||
nfFixed:
|
nfFixed:
|
||||||
Result := '0' + decs;
|
Result := intdigits + decdigits;
|
||||||
nfFixedTh:
|
nfFixedTh:
|
||||||
Result := '#,##0' + decs;
|
begin
|
||||||
|
while Length(IntDigits) < 4 do intDigits := '#' + intdigits;
|
||||||
|
System.Insert(',', intdigits, Length(intdigits)-2);
|
||||||
|
Result := intdigits + decdigits;
|
||||||
|
end;
|
||||||
nfExp:
|
nfExp:
|
||||||
Result := '0' + decs + 'E+00';
|
Result := intdigits + decdigits + 'E+00';
|
||||||
nfPercentage:
|
nfPercentage:
|
||||||
Result := '0' + decs + '%';
|
Result := intdigits + decdigits + '%';
|
||||||
nfFraction:
|
nfFraction:
|
||||||
if ADecimals = 0 then // "ADecimals" has a different meaning here...
|
if ADecimals = 0 then // "ADecimals" has a different meaning here...
|
||||||
Result := '# ??/??' // This is the default fraction format
|
Result := '# ??/??' // This is the default fraction format
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
decs := DupeString('?', ADecimals);
|
decdigits := DupeString('?', ADecimals);
|
||||||
Result := '# ' + decs + '/' + decs;
|
Result := '# ' + decdigits + '/' + decdigits;
|
||||||
end;
|
end;
|
||||||
nfCurrency, nfCurrencyRed:
|
nfCurrency, nfCurrencyRed:
|
||||||
Result := BuildCurrencyFormatString(ANumberFormat, AFormatSettings,
|
Result := BuildCurrencyFormatString(ANumberFormat, AFormatSettings,
|
||||||
@@ -2834,7 +2851,12 @@ begin
|
|||||||
case section^.Elements[el].Token of
|
case section^.Elements[el].Token of
|
||||||
nftZeroDecs:
|
nftZeroDecs:
|
||||||
section^.Decimals := section^.Elements[el].IntValue;
|
section^.Decimals := section^.Elements[el].IntValue;
|
||||||
nftIntZeroDigit, nftIntOptDigit, nftIntSpaceDigit:
|
nftIntZeroDigit:
|
||||||
|
begin
|
||||||
|
section^.MinIntDigits := section^.Elements[el].IntValue;
|
||||||
|
i := section^.Elements[el].IntValue;
|
||||||
|
end;
|
||||||
|
nftIntOptDigit, nftIntSpaceDigit:
|
||||||
i := section^.Elements[el].IntValue;
|
i := section^.Elements[el].IntValue;
|
||||||
nftFracNumSpaceDigit, nftFracNumZeroDigit:
|
nftFracNumSpaceDigit, nftFracNumZeroDigit:
|
||||||
section^.FracNumerator := section^.Elements[el].IntValue;
|
section^.FracNumerator := section^.Elements[el].IntValue;
|
||||||
|
|||||||
@@ -853,7 +853,8 @@ begin
|
|||||||
if (el+3 < nel) and (Elements[el+1].Token = nftExpChar) then
|
if (el+3 < nel) and (Elements[el+1].Token = nftExpChar) then
|
||||||
begin
|
begin
|
||||||
Result := Result + '<number:scientific-number number:decimal-places="0"';
|
Result := Result + '<number:scientific-number number:decimal-places="0"';
|
||||||
n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
// n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
||||||
|
n := FSections[ASection].MinIntDigits;
|
||||||
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
||||||
n := Elements[el+3].IntValue;
|
n := Elements[el+3].IntValue;
|
||||||
Result := Result + ' number:min-exponent-digits="' + IntToStr(n) + '"';
|
Result := Result + ' number:min-exponent-digits="' + IntToStr(n) + '"';
|
||||||
@@ -865,7 +866,8 @@ begin
|
|||||||
if (el+5 < nel) and (Elements[el+1].Token = nftDecSep) and (Elements[el+3].Token = nftExpChar)
|
if (el+5 < nel) and (Elements[el+1].Token = nftDecSep) and (Elements[el+3].Token = nftExpChar)
|
||||||
then begin
|
then begin
|
||||||
Result := Result + '<number:scientific-number';
|
Result := Result + '<number:scientific-number';
|
||||||
n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
// n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
||||||
|
n := FSections[ASection].MinIntDigits;
|
||||||
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
||||||
n := IfThen(Elements[el+2].Token = nftZeroDecs, Elements[el+2].IntValue, 1);
|
n := IfThen(Elements[el+2].Token = nftZeroDecs, Elements[el+2].IntValue, 1);
|
||||||
Result := Result + ' number:decimal-places="' + IntToStr(n) + '"';
|
Result := Result + ' number:decimal-places="' + IntToStr(n) + '"';
|
||||||
@@ -878,7 +880,8 @@ begin
|
|||||||
if (el+2 < nel) and (Elements[el+1].Token = nftDecSep) then
|
if (el+2 < nel) and (Elements[el+1].Token = nftDecSep) then
|
||||||
begin
|
begin
|
||||||
Result := Result + '<number:number';
|
Result := Result + '<number:number';
|
||||||
n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
// n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
||||||
|
n := FSections[ASection].MinIntDigits;
|
||||||
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
||||||
n := IfThen(Elements[el+2].Token = nftZeroDecs, Elements[el+2].IntValue, 1);
|
n := IfThen(Elements[el+2].Token = nftZeroDecs, Elements[el+2].IntValue, 1);
|
||||||
Result := Result + ' number:decimal-places="' + IntToStr(n) + '"';
|
Result := Result + ' number:decimal-places="' + IntToStr(n) + '"';
|
||||||
@@ -888,11 +891,18 @@ begin
|
|||||||
inc(el, 2);
|
inc(el, 2);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
(*
|
||||||
|
// Standard integer, format '#'
|
||||||
|
if (el = 0) and (nel = 1) and (Elements[el].Token = nftIntOptDigit) then
|
||||||
|
Result := Result + '<number:number number:min-integer-digits="0" number:decimal-places="0" />'
|
||||||
|
else
|
||||||
|
*)
|
||||||
// Standard integer
|
// Standard integer
|
||||||
if (el = nel-1) or (Elements[el+1].Token <> nftDecSep) then
|
if (el = nel-1) or (Elements[el+1].Token <> nftDecSep) then
|
||||||
begin
|
begin
|
||||||
Result := Result + '<number:number number:decimal-places="0"';
|
Result := Result + '<number:number number:decimal-places="0"';
|
||||||
n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
// n := IfThen(Elements[el].Token = nftIntZeroDigit, Elements[el].IntValue, 1);
|
||||||
|
n := FSections[ASection].MinIntDigits;
|
||||||
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
||||||
if (nfkHasFactor in Kind) and (Factor <> 0) then
|
if (nfkHasFactor in Kind) and (Factor <> 0) then
|
||||||
Result := Result + Format(' number:display-factor="%.0f"', [1.0/Factor]);
|
Result := Result + Format(' number:display-factor="%.0f"', [1.0/Factor]);
|
||||||
@@ -2962,13 +2972,13 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
|||||||
nodeName: String;
|
nodeName: String;
|
||||||
nf: TsNumberFormat;
|
nf: TsNumberFormat;
|
||||||
nfs: String;
|
nfs: String;
|
||||||
decs: Byte;
|
|
||||||
sint: String;
|
|
||||||
s: String;
|
s: String;
|
||||||
f: Double;
|
f: Double;
|
||||||
fracInt, fracNum, fracDenom: Integer;
|
fracInt, fracNum, fracDenom: Integer;
|
||||||
grouping: Boolean;
|
grouping: Boolean;
|
||||||
nex: Integer;
|
nex: Integer;
|
||||||
|
nint: Integer;
|
||||||
|
ndecs: Integer;
|
||||||
cs: String;
|
cs: String;
|
||||||
color: TsColor;
|
color: TsColor;
|
||||||
hasColor: Boolean;
|
hasColor: Boolean;
|
||||||
@@ -2987,9 +2997,8 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
|||||||
end else
|
end else
|
||||||
if nodeName = 'number:number' then
|
if nodeName = 'number:number' then
|
||||||
begin
|
begin
|
||||||
sint := GetAttrValue(node, 'number:min-integer-digits');
|
s := GetAttrValue(node, 'number:min-integer-digits');
|
||||||
if sint = '' then sint := '1';
|
if s <> '' then nint := StrToInt(s) else nint := 0;
|
||||||
|
|
||||||
s := GetAttrValue(node, 'number:decimal-places');
|
s := GetAttrValue(node, 'number:decimal-places');
|
||||||
if s = '' then
|
if s = '' then
|
||||||
s := GetAttrValue(node, 'decimal-places');
|
s := GetAttrValue(node, 'decimal-places');
|
||||||
@@ -2999,12 +3008,12 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
|||||||
nfs := nfs + 'General';
|
nfs := nfs + 'General';
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
decs := StrToInt(s);
|
ndecs := StrToInt(s);
|
||||||
grouping := GetAttrValue(node, 'number:grouping') = 'true';
|
grouping := GetAttrValue(node, 'number:grouping') = 'true';
|
||||||
s := GetAttrValue(node, 'number:display-factor');
|
s := GetAttrValue(node, 'number:display-factor');
|
||||||
if s <> '' then f := StrToFloat(s, FPointSeparatorSettings) else f := 1.0;
|
if s <> '' then f := StrToFloat(s, FPointSeparatorSettings) else f := 1.0;
|
||||||
nf := IfThen(grouping, nfFixedTh, nfFixed);
|
nf := IfThen(grouping, nfFixedTh, nfFixed);
|
||||||
nfs := nfs + BuildNumberFormatString(nf, Workbook.FormatSettings, decs); //, StrToInt(sint));
|
nfs := nfs + BuildNumberFormatString(nf, Workbook.FormatSettings, ndecs, nint);
|
||||||
if f <> 1.0 then begin
|
if f <> 1.0 then begin
|
||||||
nf := nfCustom;
|
nf := nfCustom;
|
||||||
while (f > 1.0) do
|
while (f > 1.0) do
|
||||||
@@ -3031,11 +3040,13 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
|||||||
if nodeName = 'number:scientific-number' then
|
if nodeName = 'number:scientific-number' then
|
||||||
begin
|
begin
|
||||||
nf := nfExp;
|
nf := nfExp;
|
||||||
|
s := GetAttrValue(node, 'number:min-integer-digits');
|
||||||
|
if s <> '' then nint := StrToInt(s) else nint := 0;
|
||||||
s := GetAttrValue(node, 'number:decimal-places');
|
s := GetAttrValue(node, 'number:decimal-places');
|
||||||
if s <> '' then decs := StrToInt(s) else decs := 0;
|
if s <> '' then ndecs := StrToInt(s) else ndecs := 0;
|
||||||
s := GetAttrValue(node, 'number:min-exponent-digits');
|
s := GetAttrValue(node, 'number:min-exponent-digits');
|
||||||
if s <> '' then nex := StrToInt(s) else nex := 1;
|
if s <> '' then nex := StrToInt(s) else nex := 1;
|
||||||
nfs := nfs + BuildNumberFormatString(nfFixed, Workbook.FormatSettings, decs);
|
nfs := nfs + BuildNumberFormatString(nfFixed, Workbook.FormatSettings, ndecs, nint);
|
||||||
nfs := nfs + 'E+' + DupeString('0', nex);
|
nfs := nfs + 'E+' + DupeString('0', nex);
|
||||||
end else
|
end else
|
||||||
if nodeName = 'number:currency-symbol' then
|
if nodeName = 'number:currency-symbol' then
|
||||||
|
|||||||
@@ -256,9 +256,11 @@ type
|
|||||||
function WriteNumber(ARow, ACol: Cardinal; ANumber: double): PCell; overload;
|
function WriteNumber(ARow, ACol: Cardinal; ANumber: double): PCell; overload;
|
||||||
procedure WriteNumber(ACell: PCell; ANumber: Double); overload;
|
procedure WriteNumber(ACell: PCell; ANumber: Double); overload;
|
||||||
function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
||||||
ANumFormat: TsNumberFormat; ADecimals: Byte = 2): PCell; overload;
|
ANumFormat: TsNumberFormat; ADecimals: Byte = 2;
|
||||||
|
AMinIntDigits: Integer = 1): PCell; overload;
|
||||||
procedure WriteNumber(ACell: PCell; ANumber: Double;
|
procedure WriteNumber(ACell: PCell; ANumber: Double;
|
||||||
ANumFormat: TsNumberFormat; ADecimals: Byte = 2); overload;
|
ANumFormat: TsNumberFormat; ADecimals: Byte = 2;
|
||||||
|
AMinIntDigits: Integer = 1); overload;
|
||||||
function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
function WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
||||||
ANumFormat: TsNumberFormat; ANumFormatString: String): PCell; overload;
|
ANumFormat: TsNumberFormat; ANumFormatString: String): PCell; overload;
|
||||||
procedure WriteNumber(ACell: PCell; ANumber: Double;
|
procedure WriteNumber(ACell: PCell; ANumber: Double;
|
||||||
@@ -4792,16 +4794,19 @@ end;
|
|||||||
@param ARow Cell row index
|
@param ARow Cell row index
|
||||||
@param ACol Cell column index
|
@param ACol Cell column index
|
||||||
@param ANumber Number to be written
|
@param ANumber Number to be written
|
||||||
@param ANumFormat Identifier for a built-in number format, e.g. nfFixed (optional)
|
@param ANumFormat Identifier for a built-in number format,
|
||||||
|
e.g. nfFixed (optional)
|
||||||
@param ADecimals Number of decimal places used for formatting (optional)
|
@param ADecimals Number of decimal places used for formatting (optional)
|
||||||
|
@param AMinIntDigits Minimum count of digits before the decimal separator
|
||||||
@return Pointer to cell created or used
|
@return Pointer to cell created or used
|
||||||
@see TsNumberFormat
|
@see TsNumberFormat
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
function TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
function TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: double;
|
||||||
ANumFormat: TsNumberFormat; ADecimals: Byte = 2): PCell;
|
ANumFormat: TsNumberFormat; ADecimals: Byte = 2;
|
||||||
|
AMinIntDigits: Integer = 1): PCell;
|
||||||
begin
|
begin
|
||||||
Result := GetCell(ARow, ACol);
|
Result := GetCell(ARow, ACol);
|
||||||
WriteNumber(Result, ANumber, ANumFormat, ADecimals);
|
WriteNumber(Result, ANumber, ANumFormat, ADecimals, AMinIntDigits);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@ ----------------------------------------------------------------------------
|
{@@ ----------------------------------------------------------------------------
|
||||||
@@ -4813,10 +4818,12 @@ end;
|
|||||||
@param ADecimals Optional number of decimal places used for formatting
|
@param ADecimals Optional number of decimal places used for formatting
|
||||||
If ANumFormat is nfFraction the ADecimals defines the
|
If ANumFormat is nfFraction the ADecimals defines the
|
||||||
digits of Numerator and denominator.
|
digits of Numerator and denominator.
|
||||||
|
@param AMinIntDigits Minimum count of digits before the decimal separator
|
||||||
@see TsNumberFormat
|
@see TsNumberFormat
|
||||||
-------------------------------------------------------------------------------}
|
-------------------------------------------------------------------------------}
|
||||||
procedure TsWorksheet.WriteNumber(ACell: PCell; ANumber: Double;
|
procedure TsWorksheet.WriteNumber(ACell: PCell; ANumber: Double;
|
||||||
ANumFormat: TsNumberFormat; ADecimals: Byte = 2);
|
ANumFormat: TsNumberFormat; ADecimals: Byte = 2;
|
||||||
|
AMinIntDigits: Integer = 1);
|
||||||
var
|
var
|
||||||
fmt: TsCellFormat;
|
fmt: TsCellFormat;
|
||||||
nfs: String;
|
nfs: String;
|
||||||
@@ -4837,7 +4844,7 @@ begin
|
|||||||
if ADecimals = 0 then ADecimals := 1;
|
if ADecimals = 0 then ADecimals := 1;
|
||||||
nfs := '# ' + DupeString('?', ADecimals) + '/' + DupeString('?', ADecimals);
|
nfs := '# ' + DupeString('?', ADecimals) + '/' + DupeString('?', ADecimals);
|
||||||
end else
|
end else
|
||||||
nfs := BuildNumberFormatString(fmt.NumberFormat, Workbook.FormatSettings, ADecimals);
|
nfs := BuildNumberFormatString(fmt.NumberFormat, Workbook.FormatSettings, ADecimals, AMinIntDigits);
|
||||||
fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs);
|
fmt.NumberFormatIndex := Workbook.AddNumberFormat(nfs);
|
||||||
end else begin
|
end else begin
|
||||||
Exclude(fmt.UsedFormattingFields, uffNumberFormat);
|
Exclude(fmt.UsedFormattingFields, uffNumberFormat);
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ type
|
|||||||
procedure TestWriteRead_MergedCells(AFormat: TsSpreadsheetFormat);
|
procedure TestWriteRead_MergedCells(AFormat: TsSpreadsheetFormat);
|
||||||
// Many XF records
|
// Many XF records
|
||||||
procedure TestWriteRead_ManyXF(AFormat: TsSpreadsheetFormat);
|
procedure TestWriteRead_ManyXF(AFormat: TsSpreadsheetFormat);
|
||||||
|
// Format strings
|
||||||
|
procedure TestWriteRead_FormatStrings(AFormat: TsSpreadsheetFormat);
|
||||||
|
|
||||||
published
|
published
|
||||||
// Writes out numbers & reads back.
|
// Writes out numbers & reads back.
|
||||||
@@ -89,6 +91,7 @@ type
|
|||||||
procedure TestWriteRead_BIFF2_MergedCells;
|
procedure TestWriteRead_BIFF2_MergedCells;
|
||||||
procedure TestWriteRead_BIFF2_NumberFormats;
|
procedure TestWriteRead_BIFF2_NumberFormats;
|
||||||
procedure TestWriteRead_BIFF2_ManyXFRecords;
|
procedure TestWriteRead_BIFF2_ManyXFRecords;
|
||||||
|
procedure TestWriteRead_BIFF2_FormatStrings;
|
||||||
// These features are not supported by Excel2 --> no test cases required!
|
// These features are not supported by Excel2 --> no test cases required!
|
||||||
// - Background
|
// - Background
|
||||||
// - BorderStyle
|
// - BorderStyle
|
||||||
@@ -107,6 +110,7 @@ type
|
|||||||
procedure TestWriteRead_BIFF5_NumberFormats;
|
procedure TestWriteRead_BIFF5_NumberFormats;
|
||||||
procedure TestWriteRead_BIFF5_TextRotation;
|
procedure TestWriteRead_BIFF5_TextRotation;
|
||||||
procedure TestWriteRead_BIFF5_WordWrap;
|
procedure TestWriteRead_BIFF5_WordWrap;
|
||||||
|
procedure TestWriteRead_BIFF5_FormatStrings;
|
||||||
|
|
||||||
{ BIFF8 Tests }
|
{ BIFF8 Tests }
|
||||||
procedure TestWriteRead_BIFF8_Alignment;
|
procedure TestWriteRead_BIFF8_Alignment;
|
||||||
@@ -120,6 +124,7 @@ type
|
|||||||
procedure TestWriteRead_BIFF8_NumberFormats;
|
procedure TestWriteRead_BIFF8_NumberFormats;
|
||||||
procedure TestWriteRead_BIFF8_TextRotation;
|
procedure TestWriteRead_BIFF8_TextRotation;
|
||||||
procedure TestWriteRead_BIFF8_WordWrap;
|
procedure TestWriteRead_BIFF8_WordWrap;
|
||||||
|
procedure TestWriteRead_BIFF8_FormatStrings;
|
||||||
|
|
||||||
{ ODS Tests }
|
{ ODS Tests }
|
||||||
procedure TestWriteRead_ODS_Alignment;
|
procedure TestWriteRead_ODS_Alignment;
|
||||||
@@ -133,6 +138,7 @@ type
|
|||||||
procedure TestWriteRead_ODS_NumberFormats;
|
procedure TestWriteRead_ODS_NumberFormats;
|
||||||
procedure TestWriteRead_ODS_TextRotation;
|
procedure TestWriteRead_ODS_TextRotation;
|
||||||
procedure TestWriteRead_ODS_WordWrap;
|
procedure TestWriteRead_ODS_WordWrap;
|
||||||
|
procedure TestWriteRead_ODS_FormatStrings;
|
||||||
|
|
||||||
{ OOXML Tests }
|
{ OOXML Tests }
|
||||||
procedure TestWriteRead_OOXML_Alignment;
|
procedure TestWriteRead_OOXML_Alignment;
|
||||||
@@ -146,6 +152,7 @@ type
|
|||||||
procedure TestWriteRead_OOXML_NumberFormats;
|
procedure TestWriteRead_OOXML_NumberFormats;
|
||||||
procedure TestWriteRead_OOXML_TextRotation;
|
procedure TestWriteRead_OOXML_TextRotation;
|
||||||
procedure TestWriteRead_OOXML_WordWrap;
|
procedure TestWriteRead_OOXML_WordWrap;
|
||||||
|
procedure TestWriteRead_OOXML_FormatStrings;
|
||||||
|
|
||||||
{ CSV Tests }
|
{ CSV Tests }
|
||||||
procedure TestWriteRead_CSV_DateTimeFormats;
|
procedure TestWriteRead_CSV_DateTimeFormats;
|
||||||
@@ -1677,6 +1684,84 @@ begin
|
|||||||
TestWriteRead_ManyXF(sfExcel2);
|
TestWriteRead_ManyXF(sfExcel2);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_FormatStrings(
|
||||||
|
AFormat: TsSpreadsheetFormat);
|
||||||
|
const
|
||||||
|
FormatStrings: Array[0..5] of string = (
|
||||||
|
'#', '#.000', '#.000E+00', '0', '0.000', '0.000E+00');
|
||||||
|
Numbers: array[0..4] of double = (
|
||||||
|
0, 1.23456789, -1.23456789, 1234.56789, -1234.56789);
|
||||||
|
var
|
||||||
|
MyWorkBook: TsWorkbook;
|
||||||
|
MyWorkSheet: TsWorksheet;
|
||||||
|
sollStr: String;
|
||||||
|
currStr: String;
|
||||||
|
currVal: Double;
|
||||||
|
r, c: Cardinal;
|
||||||
|
TempFile: String;
|
||||||
|
begin
|
||||||
|
MyWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
MyWorkSheet := MyWorkBook.AddWorksheet('Sheet');
|
||||||
|
for r := 0 to High(Numbers) do
|
||||||
|
for c := 0 to High(FormatStrings) do
|
||||||
|
MyWorksheet.WriteNumber(r, c, Numbers[r], nfCustom, FormatStrings[c]);
|
||||||
|
TempFile := NewTempFile;
|
||||||
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
|
finally
|
||||||
|
MyWorkbook.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
MyWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
MyWorkbook.ReadFromFile(TempFile, AFormat);
|
||||||
|
MyWorksheet := MyWorkbook.GetWorksheetByName('Sheet');
|
||||||
|
CheckEquals(High(Numbers), MyWorksheet.GetLastRowIndex, 'Row count mismatch');
|
||||||
|
CheckEquals(High(FormatStrings), MyWorksheet.GetLastColIndex, 'Col count mismatch');
|
||||||
|
for r := 0 to MyWorksheet.GetLastRowIndex do
|
||||||
|
for c := 0 to MyWorksheet.GetLastColIndex do begin
|
||||||
|
currStr := MyWorksheet.ReadAsText(r, c);
|
||||||
|
currVal := MyWorksheet.ReadAsNumber(r, c);
|
||||||
|
sollStr := FormatFloat(FormatStrings[c], currVal);
|
||||||
|
// Quick & dirty fix for FPC's issue with #.00E+00 showing a leading zero
|
||||||
|
if (sollStr <> '') and (sollStr[1] = '0') and
|
||||||
|
(pos('#.', FormatStrings[c]) = 1) and (pos('E', FormatStrings[c]) > 0)
|
||||||
|
then
|
||||||
|
Delete(sollStr, 1, 1);
|
||||||
|
CheckEquals(sollStr, currStr, Format('Formatted cell mismatch, FormatStr "%s", Cell %s', [
|
||||||
|
FormatStrings[c], GetCellString(r, c)]));
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
MyWorkbook.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_BIFF2_FormatStrings;
|
||||||
|
begin
|
||||||
|
TestWriteRead_FormatStrings(sfExcel2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_BIFF5_FormatStrings;
|
||||||
|
begin
|
||||||
|
TestWriteRead_FormatStrings(sfExcel5);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_BIFF8_FormatStrings;
|
||||||
|
begin
|
||||||
|
TestWriteRead_FormatStrings(sfExcel8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_OOXML_FormatStrings;
|
||||||
|
begin
|
||||||
|
TestWriteRead_FormatStrings(sfOOXML);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_ODS_FormatStrings;
|
||||||
|
begin
|
||||||
|
TestWriteRead_FormatStrings(sfOpenDocument);
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
RegisterTest(TSpreadWriteReadFormatTests);
|
RegisterTest(TSpreadWriteReadFormatTests);
|
||||||
InitSollFmtData;
|
InitSollFmtData;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ type
|
|||||||
var
|
var
|
||||||
ParserTestData: Array[0..13] of TParserTestData;
|
ParserTestData: Array[0..13] of TParserTestData;
|
||||||
|
|
||||||
RoundingTestData: Array[0..62] of TRoundingTestData = (
|
RoundingTestData: Array[0..65] of TRoundingTestData = (
|
||||||
// 0
|
// 0
|
||||||
(FormatString: '0'; Number: 1.2; SollString: '1'),
|
(FormatString: '0'; Number: 1.2; SollString: '1'),
|
||||||
(FormatString: '0'; Number: 1.9; SollString: '2'),
|
(FormatString: '0'; Number: 1.9; SollString: '2'),
|
||||||
@@ -109,7 +109,12 @@ var
|
|||||||
(FormatString: '0.0##'; Number: 1.21; SollString: '1.21'),
|
(FormatString: '0.0##'; Number: 1.21; SollString: '1.21'),
|
||||||
(FormatString: '0.0##'; Number: 1.212; SollString: '1.212'),
|
(FormatString: '0.0##'; Number: 1.212; SollString: '1.212'),
|
||||||
(FormatString: '0.0##'; Number: 1.2134; SollString: '1.213'),
|
(FormatString: '0.0##'; Number: 1.2134; SollString: '1.213'),
|
||||||
(FormatString: '0.0##'; Number: 1.2135; SollString: '1.214')
|
(FormatString: '0.0##'; Number: 1.2135; SollString: '1.214'),
|
||||||
|
|
||||||
|
// 63
|
||||||
|
(FormatString: '#'; Number: 0; SollString: ''),
|
||||||
|
(FormatString: '#'; Number: 1.2; SollString: '1'),
|
||||||
|
(FormatString: '#'; Number: -1.2; SollString: '-1')
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<CONFIG>
|
<CONFIG>
|
||||||
<ProjectOptions>
|
<ProjectOptions>
|
||||||
<Version Value="10"/>
|
<Version Value="11"/>
|
||||||
<PathDelim Value="\"/>
|
<PathDelim Value="\"/>
|
||||||
<General>
|
<General>
|
||||||
<SessionStorage Value="InProjectDir"/>
|
<SessionStorage Value="InProjectDir"/>
|
||||||
@@ -19,9 +19,10 @@
|
|||||||
<Version Value="2"/>
|
<Version Value="2"/>
|
||||||
</PublishOptions>
|
</PublishOptions>
|
||||||
<RunParams>
|
<RunParams>
|
||||||
<local>
|
<FormatVersion Value="2"/>
|
||||||
<FormatVersion Value="1"/>
|
<Modes Count="1">
|
||||||
</local>
|
<Mode0 Name="default"/>
|
||||||
|
</Modes>
|
||||||
</RunParams>
|
</RunParams>
|
||||||
<RequiredPackages Count="4">
|
<RequiredPackages Count="4">
|
||||||
<Item1>
|
<Item1>
|
||||||
|
|||||||
Reference in New Issue
Block a user