You've already forked lazarus-ccr
fpspreadsheet: Add support for number formats splitting off thousands, (Excel syntax "0.0,"), millions ("0.0,,"), etc.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4130 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -127,7 +127,7 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
TypInfo, LazUTF8, fpsutils, fpsCurrency;
|
TypInfo, Math, LazUTF8, fpsutils, fpsCurrency;
|
||||||
|
|
||||||
|
|
||||||
function CreateNumFormatParams(AWorkbook: TsWorkbook;
|
function CreateNumFormatParams(AWorkbook: TsWorkbook;
|
||||||
@@ -315,6 +315,13 @@ begin
|
|||||||
FStatus := psErrMultipleExpChars
|
FStatus := psErrMultipleExpChars
|
||||||
else
|
else
|
||||||
section^.Kind := section^.Kind + [nfkExp];
|
section^.Kind := section^.Kind + [nfkExp];
|
||||||
|
nftFactor:
|
||||||
|
if section^.Elements[el].IntValue <> 0 then
|
||||||
|
begin
|
||||||
|
section^.Elements[el].FloatValue := IntPower(10, -3*section^.Elements[el].IntValue);
|
||||||
|
section^.Factor := section^.Elements[el].FloatValue;
|
||||||
|
section^.Kind := section^.Kind + [nfkHasFactor];
|
||||||
|
end;
|
||||||
nftFracSymbol:
|
nftFracSymbol:
|
||||||
if (nfkFraction in section^.Kind) then
|
if (nfkFraction in section^.Kind) then
|
||||||
FStatus := psErrMultipleFracSymbols
|
FStatus := psErrMultipleFracSymbols
|
||||||
@@ -941,6 +948,8 @@ end;
|
|||||||
procedure TsNumFormatParser.ScanAndCount(ATestChar: Char; out ACount: Integer);
|
procedure TsNumFormatParser.ScanAndCount(ATestChar: Char; out ACount: Integer);
|
||||||
begin
|
begin
|
||||||
ACount := 0;
|
ACount := 0;
|
||||||
|
if FToken <> ATestChar then
|
||||||
|
exit;
|
||||||
repeat
|
repeat
|
||||||
inc(ACount);
|
inc(ACount);
|
||||||
FToken := NextToken;
|
FToken := NextToken;
|
||||||
@@ -1236,7 +1245,7 @@ procedure TsNumFormatParser.ScanNumber;
|
|||||||
var
|
var
|
||||||
hasDecSep: Boolean;
|
hasDecSep: Boolean;
|
||||||
isFrac: Boolean;
|
isFrac: Boolean;
|
||||||
n: Integer;
|
n, m: Integer;
|
||||||
el: Integer;
|
el: Integer;
|
||||||
savedCurrent: PChar;
|
savedCurrent: PChar;
|
||||||
begin
|
begin
|
||||||
@@ -1254,12 +1263,13 @@ begin
|
|||||||
savedCurrent := FCurrent;
|
savedCurrent := FCurrent;
|
||||||
if not (hasDecSep or isFrac) and (n = 1) and (FToken = ',') then
|
if not (hasDecSep or isFrac) and (n = 1) and (FToken = ',') then
|
||||||
begin
|
begin
|
||||||
|
m := 0;
|
||||||
FToken := NextToken;
|
FToken := NextToken;
|
||||||
ScanAndCount('#', n);
|
ScanAndCount('#', n);
|
||||||
case n of
|
case n of
|
||||||
0: begin
|
0: begin
|
||||||
FToken := PrevToken;
|
|
||||||
ScanAndCount('0', n);
|
ScanAndCount('0', n);
|
||||||
|
ScanAndCount(',', m);
|
||||||
FToken := prevToken;
|
FToken := prevToken;
|
||||||
if n = 3 then
|
if n = 3 then
|
||||||
AddElement(nftIntTh, 3)
|
AddElement(nftIntTh, 3)
|
||||||
@@ -1268,6 +1278,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
1: begin
|
1: begin
|
||||||
ScanAndCount('0', n);
|
ScanAndCount('0', n);
|
||||||
|
ScanAndCount(',', m);
|
||||||
FToken := prevToken;
|
FToken := prevToken;
|
||||||
if n = 2 then
|
if n = 2 then
|
||||||
AddElement(nftIntTh, 2)
|
AddElement(nftIntTh, 2)
|
||||||
@@ -1276,6 +1287,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
2: begin
|
2: begin
|
||||||
ScanAndCount('0', n);
|
ScanAndCount('0', n);
|
||||||
|
ScanAndCount(',', m);
|
||||||
FToken := prevToken;
|
FToken := prevToken;
|
||||||
if (n = 1) then
|
if (n = 1) then
|
||||||
AddElement(nftIntTh, 1)
|
AddElement(nftIntTh, 1)
|
||||||
@@ -1283,6 +1295,8 @@ begin
|
|||||||
FCurrent := savedCurrent;
|
FCurrent := savedCurrent;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
if m > 0 then
|
||||||
|
AddElement(nftFactor, m);
|
||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
FToken := PrevToken;
|
FToken := PrevToken;
|
||||||
@@ -1297,6 +1311,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
'0': begin
|
'0': begin
|
||||||
ScanAndCount('0', n);
|
ScanAndCount('0', n);
|
||||||
|
ScanAndCount(',', m);
|
||||||
FToken := PrevToken;
|
FToken := PrevToken;
|
||||||
if hasDecSep then
|
if hasDecSep then
|
||||||
AddElement(nftZeroDecs, n)
|
AddElement(nftZeroDecs, n)
|
||||||
@@ -1305,6 +1320,8 @@ begin
|
|||||||
AddElement(nftFracDenomZeroDigit, n)
|
AddElement(nftFracDenomZeroDigit, n)
|
||||||
else
|
else
|
||||||
AddElement(nftIntZeroDigit, n);
|
AddElement(nftIntZeroDigit, n);
|
||||||
|
if m > 0 then
|
||||||
|
AddElement(nftFactor, m);
|
||||||
end;
|
end;
|
||||||
'1'..'9':
|
'1'..'9':
|
||||||
begin
|
begin
|
||||||
|
@@ -620,6 +620,9 @@ begin
|
|||||||
nftPercent:
|
nftPercent:
|
||||||
Result := Result + '<number:text>%</number:text>';
|
Result := Result + '<number:text>%</number:text>';
|
||||||
|
|
||||||
|
nftFactor:
|
||||||
|
;
|
||||||
|
|
||||||
nftCurrSymbol:
|
nftCurrSymbol:
|
||||||
Result := Result + '<number:currency-symbol>' + Elements[el].TextValue + '</number:currency-symbol>';
|
Result := Result + '<number:currency-symbol>' + Elements[el].TextValue + '</number:currency-symbol>';
|
||||||
|
|
||||||
@@ -635,6 +638,8 @@ begin
|
|||||||
end else
|
end else
|
||||||
if (el = nel-1) or (Elements[el+1].Token <> nftDecSep) then
|
if (el = nel-1) or (Elements[el+1].Token <> nftDecSep) then
|
||||||
Result := Result + ' number:decimal-places="0"';
|
Result := Result + ' number:decimal-places="0"';
|
||||||
|
if (nfkHasFactor in Kind) and (Factor <> 0) then
|
||||||
|
Result := Result + Format(' number:display-factor="%.0f"', [1.0/Factor]);
|
||||||
Result := Result + ' />';
|
Result := Result + ' />';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -740,6 +745,8 @@ begin
|
|||||||
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) + '"';
|
||||||
|
if (nfkHasFactor in Kind) and (Factor <> 0) then
|
||||||
|
Result := Result + Format(' number:display-factor="%.0f"', [1.0/Factor]);
|
||||||
Result := Result + ' />';
|
Result := Result + ' />';
|
||||||
inc(el, 2);
|
inc(el, 2);
|
||||||
end
|
end
|
||||||
@@ -750,6 +757,8 @@ 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);
|
||||||
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
Result := Result + ' number:min-integer-digits="' + IntToStr(n) + '"';
|
||||||
|
if (nfkHasFactor in Kind) and (Factor <> 0) then
|
||||||
|
Result := Result + Format(' number:display-factor="%.0f"', [1.0/Factor]);
|
||||||
Result := Result + ' />';
|
Result := Result + ' />';
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -2227,6 +2236,7 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
|||||||
nfs: String;
|
nfs: String;
|
||||||
decs: Byte;
|
decs: Byte;
|
||||||
s: String;
|
s: String;
|
||||||
|
f: Double;
|
||||||
fracInt, fracNum, fracDenom: Integer;
|
fracInt, fracNum, fracDenom: Integer;
|
||||||
grouping: Boolean;
|
grouping: Boolean;
|
||||||
nex: Integer;
|
nex: Integer;
|
||||||
@@ -2253,8 +2263,18 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
|
|||||||
if s = '' then s := GetAttrValue(node, 'decimal-places');
|
if s = '' then s := GetAttrValue(node, 'decimal-places');
|
||||||
if s <> '' then decs := StrToInt(s) else decs := 0;
|
if s <> '' then decs := StrToInt(s) else decs := 0;
|
||||||
grouping := GetAttrValue(node, 'number:grouping') = 'true';
|
grouping := GetAttrValue(node, 'number:grouping') = 'true';
|
||||||
|
s := GetAttrValue(node, 'number:display-factor');
|
||||||
|
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);
|
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 else
|
end else
|
||||||
if nodeName = 'number:fraction' then
|
if nodeName = 'number:fraction' then
|
||||||
begin
|
begin
|
||||||
|
@@ -473,6 +473,7 @@ type
|
|||||||
nftExpSign, // '+' or '-' in exponent
|
nftExpSign, // '+' or '-' in exponent
|
||||||
nftExpDigits, // '0' digits in exponent, count stored in IntValue
|
nftExpDigits, // '0' digits in exponent, count stored in IntValue
|
||||||
nftPercent, // '%' percent symbol
|
nftPercent, // '%' percent symbol
|
||||||
|
nftFactor, // thousand separators at end of format string, each one divides value by 1000
|
||||||
nftFracSymbol, // '/' fraction symbol
|
nftFracSymbol, // '/' fraction symbol
|
||||||
nftFracNumOptDigit, // '#' in numerator, count stored in IntValue
|
nftFracNumOptDigit, // '#' in numerator, count stored in IntValue
|
||||||
nftFracNumSpaceDigit, // '?' in numerator, count stored in IntValue
|
nftFracNumSpaceDigit, // '?' in numerator, count stored in IntValue
|
||||||
@@ -502,7 +503,7 @@ type
|
|||||||
TsNumFormatElements = array of TsNumFormatElement;
|
TsNumFormatElements = array of TsNumFormatElement;
|
||||||
|
|
||||||
TsNumFormatKind = (nfkPercent, nfkExp, nfkCurrency, nfkFraction,
|
TsNumFormatKind = (nfkPercent, nfkExp, nfkCurrency, nfkFraction,
|
||||||
nfkDate, nfkTime, nfkTimeInterval, nfkHasColor, nfkHasThSep);
|
nfkDate, nfkTime, nfkTimeInterval, nfkHasColor, nfkHasThSep, nfkHasFactor);
|
||||||
TsNumFormatKinds = set of TsNumFormatKind;
|
TsNumFormatKinds = set of TsNumFormatKind;
|
||||||
|
|
||||||
TsNumFormatSection = record
|
TsNumFormatSection = record
|
||||||
@@ -510,6 +511,7 @@ type
|
|||||||
Kind: TsNumFormatKinds;
|
Kind: TsNumFormatKinds;
|
||||||
NumFormat: TsNumberFormat;
|
NumFormat: TsNumberFormat;
|
||||||
Decimals: Byte;
|
Decimals: Byte;
|
||||||
|
Factor: Double;
|
||||||
FracInt: Integer;
|
FracInt: Integer;
|
||||||
FracNumerator: Integer;
|
FracNumerator: Integer;
|
||||||
FracDenominator: Integer;
|
FracDenominator: Integer;
|
||||||
@@ -721,7 +723,6 @@ const
|
|||||||
HEADER_FOOTER_INDEX_FIRST = 0;
|
HEADER_FOOTER_INDEX_FIRST = 0;
|
||||||
HEADER_FOOTER_INDEX_ODD = 1;
|
HEADER_FOOTER_INDEX_ODD = 1;
|
||||||
HEADER_FOOTER_INDEX_EVEN = 2;
|
HEADER_FOOTER_INDEX_EVEN = 2;
|
||||||
HEADER_FOOTER_INDEX_ODDEVEN = 1;
|
|
||||||
HEADER_FOOTER_INDEX_ALL = 1;
|
HEADER_FOOTER_INDEX_ALL = 1;
|
||||||
|
|
||||||
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
|
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
|
||||||
@@ -907,7 +908,7 @@ end;
|
|||||||
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
|
function BuildFormatStringFromSection(const ASection: TsNumFormatSection): String;
|
||||||
var
|
var
|
||||||
element: TsNumFormatElement;
|
element: TsNumFormatElement;
|
||||||
i: Integer;
|
i, n: Integer;
|
||||||
begin
|
begin
|
||||||
Result := '';
|
Result := '';
|
||||||
|
|
||||||
@@ -940,6 +941,16 @@ begin
|
|||||||
Result := Result + '/';
|
Result := Result + '/';
|
||||||
nftPercent:
|
nftPercent:
|
||||||
Result := Result + '%';
|
Result := Result + '%';
|
||||||
|
nftFactor:
|
||||||
|
if element.IntValue <> 0 then
|
||||||
|
begin
|
||||||
|
n := element.IntValue;
|
||||||
|
while (n > 0) do
|
||||||
|
begin
|
||||||
|
Result := Result + ',';
|
||||||
|
dec(n);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
nftSpace:
|
nftSpace:
|
||||||
Result := Result + ' ';
|
Result := Result + ' ';
|
||||||
nftText:
|
nftText:
|
||||||
@@ -1075,6 +1086,10 @@ begin
|
|||||||
exit;
|
exit;
|
||||||
if Sections[i].Decimals <> ASections[i].Decimals then
|
if Sections[i].Decimals <> ASections[i].Decimals then
|
||||||
exit;
|
exit;
|
||||||
|
{
|
||||||
|
if Sections[i].Factor <> ASections[i].Factor then
|
||||||
|
exit;
|
||||||
|
}
|
||||||
if Sections[i].FracInt <> ASections[i].FracInt then
|
if Sections[i].FracInt <> ASections[i].FracInt then
|
||||||
exit;
|
exit;
|
||||||
if Sections[i].FracNumerator <> ASections[i].FracNumerator then
|
if Sections[i].FracNumerator <> ASections[i].FracNumerator then
|
||||||
@@ -1099,7 +1114,7 @@ begin
|
|||||||
nftHour, nftMinute, nftSecond, nftMilliseconds,
|
nftHour, nftMinute, nftSecond, nftMilliseconds,
|
||||||
nftMonthMinute,
|
nftMonthMinute,
|
||||||
nftIntOptDigit, nftIntZeroDigit, nftIntSpaceDigit, nftIntTh,
|
nftIntOptDigit, nftIntZeroDigit, nftIntSpaceDigit, nftIntTh,
|
||||||
nftZeroDecs, nftOptDecs, nftSpaceDecs, nftExpDigits,
|
nftZeroDecs, nftOptDecs, nftSpaceDecs, nftExpDigits, nftFactor,
|
||||||
nftFracNumOptDigit, nftFracNumSpaceDigit, nftFracNumZeroDigit,
|
nftFracNumOptDigit, nftFracNumSpaceDigit, nftFracNumZeroDigit,
|
||||||
nftFracDenomOptDigit, nftFracDenomSpaceDigit, nftFracDenomZeroDigit,
|
nftFracDenomOptDigit, nftFracDenomSpaceDigit, nftFracDenomZeroDigit,
|
||||||
nftColor:
|
nftColor:
|
||||||
|
@@ -2967,6 +2967,8 @@ begin
|
|||||||
|
|
||||||
if nfkPercent in section.Kind then
|
if nfkPercent in section.Kind then
|
||||||
AValue := AValue * 100.0;
|
AValue := AValue * 100.0;
|
||||||
|
if nfkHasFactor in section.Kind then
|
||||||
|
AValue := AValue * section.Factor;
|
||||||
if nfkTime in section.Kind then
|
if nfkTime in section.Kind then
|
||||||
DecodeTime(AValue, hr, min, sec, ms);
|
DecodeTime(AValue, hr, min, sec, ms);
|
||||||
if nfkDate in section.Kind then
|
if nfkDate in section.Kind then
|
||||||
|
Reference in New Issue
Block a user