fpspreadsheet: Extend number format parser to accept the keyword "General" in custom formats

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4161 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-05-29 21:35:07 +00:00
parent a05a385c8d
commit e2ddc7c705
6 changed files with 72 additions and 21 deletions

View File

@ -23,7 +23,8 @@ const
psErrMultipleCurrSymbols = 9; psErrMultipleCurrSymbols = 9;
psErrMultipleFracSymbols = 10; psErrMultipleFracSymbols = 10;
psErrMultipleExpChars = 11; psErrMultipleExpChars = 11;
psAmbiguousSymbol = 12; psErrGeneralExpected = 12;
psAmbiguousSymbol = 13;
type type
@ -54,7 +55,7 @@ type
{ Administration while scanning } { Administration while scanning }
procedure AddElement(AToken: TsNumFormatToken; AText: String); overload; procedure AddElement(AToken: TsNumFormatToken; AText: String); overload;
procedure AddElement(AToken: TsNumFormatToken; AIntValue: Integer); overload; procedure AddElement(AToken: TsNumFormatToken; AIntValue: Integer=0); overload;
procedure AddElement(AToken: TsNumFormatToken; AFloatValue: Double); overload; procedure AddElement(AToken: TsNumFormatToken; AFloatValue: Double); overload;
procedure AddSection; procedure AddSection;
procedure DeleteElement(ASection, AIndex: Integer); procedure DeleteElement(ASection, AIndex: Integer);
@ -72,6 +73,7 @@ type
procedure ScanCurrSymbol; procedure ScanCurrSymbol;
procedure ScanDateTime; procedure ScanDateTime;
procedure ScanFormat; procedure ScanFormat;
procedure ScanGeneral;
procedure ScanNumber; procedure ScanNumber;
procedure ScanQuotedText; procedure ScanQuotedText;
// Main scanner // Main scanner
@ -190,7 +192,7 @@ begin
FSections[FCurrSection].Elements[n].TextValue := AText; FSections[FCurrSection].Elements[n].TextValue := AText;
end; end;
procedure TsNumFormatParser.AddElement(AToken: TsNumFormatToken; AIntValue: Integer); procedure TsNumFormatParser.AddElement(AToken: TsNumFormatToken; AIntValue: Integer=0);
var var
n: Integer; n: Integer;
begin begin
@ -359,7 +361,10 @@ begin
section^.Kind := section^.Kind + [nfkTimeInterval]; section^.Kind := section^.Kind + [nfkTimeInterval];
end; end;
nftColor: nftColor:
section^.Kind := section^.Kind + [nfkHasColor]; begin
section^.Kind := section^.Kind + [nfkHasColor];
section^.Color := section^.Elements[el].IntValue;
end;
nftIntTh: nftIntTh:
section^.Kind := section^.Kind + [nfkHasThSep]; section^.Kind := section^.Kind + [nfkHasThSep];
end; end;
@ -932,8 +937,11 @@ begin
FStatus := psOK; FStatus := psOK;
AddSection; AddSection;
if (AFormatString = '') or SameText(AFormatString, 'General') then if (AFormatString = '') then
begin
AddElement(nftGeneral);
exit; exit;
end;
FStart := @AFormatString[1]; FStart := @AFormatString[1];
FEnd := FStart + Length(AFormatString); FEnd := FStart + Length(AFormatString);
@ -941,6 +949,7 @@ begin
FToken := FCurrent^; FToken := FCurrent^;
while (FCurrent < FEnd) and (FStatus = psOK) do begin while (FCurrent < FEnd) and (FStatus = psOK) do begin
case FToken of case FToken of
'G','g': ScanGeneral;
'[': ScanBrackets; '[': ScanBrackets;
'"': ScanQuotedText; '"': ScanQuotedText;
':': AddElement(nftDateTimeSep, ':'); ':': AddElement(nftDateTimeSep, ':');
@ -1264,6 +1273,8 @@ begin
ScanAMPM; ScanAMPM;
FToken := PrevToken; FToken := PrevToken;
end; end;
'G', 'g':
ScanGeneral;
';': // End of the section. Important: Cursor must stay on ';' ';': // End of the section. Important: Cursor must stay on ';'
begin begin
AddSection; AddSection;
@ -1276,6 +1287,26 @@ begin
end; end;
end; end;
{ Scans for the word "General", it may be used like other tokens }
procedure TsNumFormatParser.ScanGeneral;
begin
FStatus := psErrGeneralExpected;
FToken := NextToken;
if not (FToken in ['e', 'E']) then exit;
FToken := NextToken;
if not (FToken in ['n', 'N']) then exit;
FToken := NextToken;
if not (FToken in ['e', 'E']) then exit;
FToken := NextToken;
if not (FToken in ['r', 'R']) then exit;
FToken := NextToken;
if not (FToken in ['a', 'A']) then exit;
FToken := NextToken;
if not (FToken in ['l', 'L']) then exit;
AddElement(nftGeneral);
FStatus := psOK;
end;
{ Scans a floating point format. Procedure is left with the cursor at the last { Scans a floating point format. Procedure is left with the cursor at the last
character of the format. } character of the format. }
procedure TsNumFormatParser.ScanNumber; procedure TsNumFormatParser.ScanNumber;
@ -1427,7 +1458,8 @@ begin
end; end;
end; end;
end; end;
'G', 'g':
ScanGeneral;
else else
FToken := PrevToken; FToken := PrevToken;
Exit; Exit;

View File

@ -626,6 +626,9 @@ begin
nftCurrSymbol: nftCurrSymbol:
Result := Result + '<number:currency-symbol>' + Elements[el].TextValue + '</number:currency-symbol>'; Result := Result + '<number:currency-symbol>' + Elements[el].TextValue + '</number:currency-symbol>';
nftGeneral:
Result := Result + '<number:number number:min-integer-digits="1" />';
nftIntTh: nftIntTh:
begin begin
Result := Result + '<number:number number:min-integer-digits="1" number:grouping="true"'; Result := Result + '<number:number number:min-integer-digits="1" number:grouping="true"';
@ -2256,19 +2259,27 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
if nodeName = 'number:number' then if nodeName = 'number:number' then
begin begin
s := GetAttrValue(node, 'number:decimal-places'); s := GetAttrValue(node, 'number:decimal-places');
if s = '' then s := GetAttrValue(node, 'decimal-places'); if s = '' then
if s <> '' then decs := StrToInt(s) else decs := 0; s := GetAttrValue(node, 'decimal-places');
grouping := GetAttrValue(node, 'number:grouping') = 'true'; if s = '' then
s := GetAttrValue(node, 'number:display-factor'); begin
if s <> '' then f := StrToFloat(s, FPointSeparatorSettings) else f := 1.0; if nfs='' then nf := nfGeneral else nf := nfCustom;
nf := IfThen(grouping, nfFixedTh, nfFixed); nfs := nfs + 'General';
nfs := nfs + BuildNumberFormatString(nf, Workbook.FormatSettings, decs); end else
if f <> 1.0 then begin begin
nf := nfCustom; decs := StrToInt(s);
while (f > 1.0) do grouping := GetAttrValue(node, 'number:grouping') = 'true';
begin s := GetAttrValue(node, 'number:display-factor');
nfs := nfs + ','; if s <> '' then f := StrToFloat(s, FPointSeparatorSettings) else f := 1.0;
f := f / 1000; nf := IfThen(grouping, nfFixedTh, nfFixed);
nfs := nfs + BuildNumberFormatString(nf, Workbook.FormatSettings, decs);
if f <> 1.0 then begin
nf := nfCustom;
while (f > 1.0) do
begin
nfs := nfs + ',';
f := f / 1000;
end;
end; end;
end; end;
end else end else

View File

@ -502,6 +502,7 @@ type
{@@ Tokens used by the elements of the number format parser } {@@ Tokens used by the elements of the number format parser }
TsNumFormatToken = ( TsNumFormatToken = (
nftGeneral, // token for "general" number format
nftText, // must be quoted, stored in TextValue nftText, // must be quoted, stored in TextValue
nftThSep, // ',', replaced by FormatSettings.ThousandSeparator nftThSep, // ',', replaced by FormatSettings.ThousandSeparator
nftDecSep, // '.', replaced by FormatSettings.DecimalSeparator nftDecSep, // '.', replaced by FormatSettings.DecimalSeparator
@ -970,6 +971,8 @@ begin
for i := 0 to High(ASection.Elements) do begin for i := 0 to High(ASection.Elements) do begin
element := ASection.Elements[i]; element := ASection.Elements[i];
case element.Token of case element.Token of
nftGeneral:
Result := Result + 'General';
nftIntOptDigit, nftOptDecs, nftFracNumOptDigit, nftFracDenomOptDigit: nftIntOptDigit, nftOptDecs, nftFracNumOptDigit, nftFracDenomOptDigit:
if element.IntValue > 0 then if element.IntValue > 0 then
Result := Result + DupeString('#', element.IntValue); Result := Result + DupeString('#', element.IntValue);

View File

@ -2880,6 +2880,13 @@ begin
el := 0; el := 0;
while (el < numEl) do begin while (el < numEl) do begin
if section.Elements[el].Token = nftGeneral then
begin
s := FloatToStrF(AValue, ffGeneral, 20, 20, fs);
if (sidx=0) and isNeg then s := '-' + s;
Result := Result + s;
end
else
// Integer token: can be the start of a number, exp, or mixed fraction format // Integer token: can be the start of a number, exp, or mixed fraction format
// Cases with thousand separator are handled here as well. // Cases with thousand separator are handled here as well.
if section.Elements[el].Token in (INT_TOKENS + [nftIntTh]) then begin if section.Elements[el].Token in (INT_TOKENS + [nftIntTh]) then begin

View File

@ -440,7 +440,6 @@ end;*)
procedure TsSpreadBIFF2Reader.ReadFormat(AStream: TStream); procedure TsSpreadBIFF2Reader.ReadFormat(AStream: TStream);
var var
len: byte; len: byte;
fmtIndex: Integer;
fmtString: AnsiString; fmtString: AnsiString;
nfs: String; nfs: String;
begin begin

View File

@ -1200,7 +1200,6 @@ procedure TsSpreadBIFF5Writer.WriteFont(AStream: TStream; AFont: TsFont);
var var
Len: Byte; Len: Byte;
optn: Word; optn: Word;
cidx: Integer;
begin begin
if AFont = nil then // this happens for FONT4 in case of BIFF if AFont = nil then // this happens for FONT4 in case of BIFF
exit; exit;