fpspreadsheet: Add support for fraction formats having a fixed denominator ("# ?/4" for quarters, etc.)

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4101 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-04-29 16:23:07 +00:00
parent dc8ad5acde
commit 3a2b5f2aad
5 changed files with 123 additions and 28 deletions

View File

@ -177,9 +177,19 @@ begin
AddToList(nfcFraction, '# ?/?');
AddToList(nfcFraction, '# ??/??');
AddToList(nfcFraction, '# ???/???');
AddToList(nfcFraction, '# ?/2');
AddToList(nfcFraction, '# ?/4');
AddToList(nfcFraction, '# ?/8');
AddToList(nfcFraction, '# ?/16');
AddToList(nfcFraction, '# ?/32');
AddToList(nfcFraction, '?/?');
AddToList(nfcFraction, '?/??');
AddToList(nfcFraction, '?/???');
AddToList(nfcFraction, '?/2');
AddToList(nfcFraction, '?/4');
AddToList(nfcFraction, '?/8');
AddToList(nfcFraction, '?/16');
AddToList(nfcFraction, '?/32');
AddToList(nfcCurrency, '#,##0 [$$];-#,##0 [$$]');
AddToList(nfcCurrency, '#,##0.00 [$$];-#,##0.00 [$$]');

View File

@ -1307,6 +1307,20 @@ begin
else
AddElement(nftIntZeroDigit, n);
end;
'1'..'9':
begin
if isFrac then
begin
n := 0;
while (FToken in ['1'..'9','0']) do //and (FToken <= FEnd) do
begin
n := n*10 + StrToInt(FToken);
FToken := nextToken;
end;
AddElement(nftFracDenom, n);
end else
AddElement(nftText, FToken);
end;
'?': begin
ScanAndCount('?', n);
FToken := PrevToken;

View File

@ -318,6 +318,7 @@ var
mask: String;
timeIntervalStr: String;
styleMapStr: String;
int,num,denom: Integer;
begin
Result := '';
@ -391,28 +392,72 @@ begin
end;
nftFracNumZeroDigit, nftFracNumOptDigit, nftFracNumSpaceDigit:
if (el+2 < nel) and (Elements[el+1].Token = nftFracSymbol) then
begin
Result := Result +
'<number:fraction' +
' number:min-numerator-digits="' + IntToStr(Elements[el].IntValue) +
'" number:min-denominator-digits="' + IntToStr(Elements[el+2].IntValue) +
'" />';
inc(el, 2);
num := Elements[el].IntValue;
inc(el);
while (el < nel) and (Elements[el].Token in [nftSpace, nftText, nftEscaped]) do
inc(el);
if (el < nel) and (Elements[el].Token <> nftFracSymbol) then
Continue;
while (el < nel) and (Elements[el].Token in [nftSpace, nftText, nftEscaped]) do
inc(el);
if (el < nel) and
(Elements[el].Token in [nftFracDenomOptDigit, nftFracDenomSpaceDigit, nftFracDenomZeroDigit, nftFracDenom])
then
denom := Elements[el].IntValue
else
Continue;
if Elements[el].Token = nftFracDenom then // fixed denominator
Result := Result +
'<number:fraction' +
' number:min-numerator-digits="' + IntToStr(num) +
'" number:min-denominator-digits="' + IntToStr(num) +
'" number:denominator-value="' + IntToStr(denom) +
'" />'
else
Result := Result +
'<number:fraction' +
' number:min-numerator-digits="' + IntToStr(num) +
'" number:min-denominator-digits="' + IntToStr(num) +
'" />'
end;
nftIntZeroDigit, nftIntOptDigit, nftIntSpaceDigit:
begin
// Mixed fraction
if (el+4 < nel) and (Elements[el+1].Token = nftSpace) and (Elements[el+3].Token = nftFracSymbol)
then begin
Result := Result +
'<number:fraction' +
' number:min-integer-digits="' + IntToStr(Elements[el].IntValue) +
'" number:min-numerator-digits="' + IntToStr(Elements[el+2].IntValue) +
'" number:min-denominator-digits="' + IntToStr(Elements[el+4].IntValue) +
'" />';
inc(el, 4);
if nfkFraction in Kind then
begin
int := Elements[el].IntValue;
inc(el);
while (el < nel) and not
(Elements[el].Token in [nftFracNumZeroDigit, nftFracNumOptDigit, nftFracNumSpaceDigit])
do
inc(el);
if el = nel then
Continue;
num := Elements[el].IntValue;
while (el < nel) and not
(Elements[el].Token in [nftFracDenomZeroDigit, nftFracDenomOptDigit, nftFracDenomSpaceDigit, nftFracDenom])
do
inc(el);
if el = nel then
Continue;
denom := Elements[el].IntValue;
if (Elements[el].Token = nftFracDenom) then
Result := Result +
'<number:fraction' +
' number:min-integer-digits="' + IntToStr(int) +
'" number:min-numerator-digits="' + IntToStr(num) +
'" number:min-denominator-digits="' + IntToStr(num) +
'" number:denominator-value="' + IntToStr(denom) +
'" />'
else
Result := Result +
'<number:fraction' +
' number:min-integer-digits="' + IntToStr(int) +
'" number:min-numerator-digits="' + IntToStr(num) +
'" number:min-denominator-digits="' + IntToStr(denom) +
'" />';
end
else
// Scientific, no decimals
@ -1624,6 +1669,8 @@ procedure TsSpreadOpenDocReader.ReadNumFormats(AStylesNode: TDOMNode);
if s <> '' then fracNum := StrToInt(s) else fracNum := 0;
s := GetAttrValue(node, 'number:min-denominator-digits');
if s <> '' then fracDenom := StrToInt(s) else fracDenom := 0;
s := GetAttrValue(node, 'number:denominator-value');
if s <> '' then fracDenom := -StrToInt(s);
nfs := nfs + BuildFractionFormatString(fracInt > 0, fracNum, fracDenom);
end else
if nodeName = 'number:scientific-number' then

View File

@ -480,6 +480,7 @@ type
nftFracDenomOptDigit, // '#' in denominator, count stored in IntValue
nftFracDenomSpaceDigit,// '?' in denominator, count stored in IntValue
nftFracDenomZeroDigit, // '0' in denominator, count stored in IntValue
nftFracDenom, // specified denominator, value stored in IntValue
nftCurrSymbol, // e.g., '"$"', stored in TextValue
nftCountry,
nftColor, // e.g., '[red]', Color in IntValue
@ -866,6 +867,8 @@ begin
nftIntSpaceDigit, nftSpaceDecs, nftFracNumSpaceDigit, nftFracDenomSpaceDigit:
if element.Intvalue > 0 then
Result := result + DupeString('?', element.IntValue);
nftFracDenom:
Result := Result + IntToStr(element.IntValue);
nftIntTh:
case element.Intvalue of
0: Result := Result + '#,###';

View File

@ -1179,9 +1179,14 @@ end;
function BuildFractionFormatString(AMixedFraction: Boolean;
ANumeratorDigits, ADenominatorDigits: Integer): String;
begin
Result := Format('%s/%s', [
DupeString('#', ANumeratorDigits), DupeString('#', ADenominatorDigits)
]);
if ADenominatorDigits < 0 then // a negative value indicates a fixed denominator value
Result := Format('%s/%d', [
DupeString('?', ANumeratorDigits), -ADenominatorDigits
])
else
Result := Format('%s/%s', [
DupeString('?', ANumeratorDigits), DupeString('?', ADenominatorDigits)
]);
if AMixedFraction then
Result := '# ' + Result;
end;
@ -2413,7 +2418,7 @@ const
FRACNUM_TOKENS: TsNumFormatTokenSet =
[nftFracNumOptDigit, nftFracNumZeroDigit, nftFracNumSpaceDigit];
FRACDENOM_TOKENS: TsNumFormatTokenSet =
[nftFracDenomOptDigit, nftFracDenomZeroDigit, nftFracDenomSpaceDigit];
[nftFracDenomOptDigit, nftFracDenomZeroDigit, nftFracDenomSpaceDigit, nftFracDenom];
EXP_TOKENS: TsNumFormatTokenSet =
[nftExpDigits]; // todo: expand by optional digits (0.00E+#)
@ -2490,12 +2495,12 @@ begin
// Here follows the ordinary fraction (no integer split off); sample format "??/??"
while (i < numEl) and (AElements[i].Token in FRACNUM_TOKENS) do inc(i);
while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do inc(i);
if (AElements[i].Token <> nftFracSymbol) then
if (i = numEl) or (AElements[i].Token <> nftFracSymbol) then
exit(False);
inc(i);
while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do inc(i);
if not (AElements[i].Token in FRACDENOM_TOKENS) then
if (i = numEl) or (not (AElements[i].Token in FRACDENOM_TOKENS)) then
exit(false);
while (i < numEL) and (AElements[i].Token in FRACDENOM_TOKENS) do
@ -2504,6 +2509,7 @@ begin
nftFracDenomZeroDigit : inc(digits, AElements[i].IntValue);
nftFracDenomSpaceDigit: inc(digits, AElements[i].IntValue);
nftFracDenomOptDigit : inc(digits, AElements[i].IntValue);
nftFracDenom : digits := -AElements[i].IntValue; // "-" indicates a literal denominator value!
end;
inc(i);
end;
@ -2723,8 +2729,10 @@ begin
snumsymspace := '';
ssymdenomspace := '';
sfrsym := '/';
maxDenom := Round(IntPower(10, ADigits));
prec := 1/maxDenom;
if ADigits >= 0 then begin
maxDenom := Round(IntPower(10, ADigits));
prec := 1/maxDenom;
end;
numEl := Length(AElements);
i := AIndex;
@ -2737,10 +2745,16 @@ begin
AValue := frac(AValue);
end else
frint := 0;
FloatToFraction(AValue, prec, MaxInt, maxdenom, frnum, frdenom);
if ADigits >= 0 then
FloatToFraction(AValue, prec, MaxInt, maxdenom, frnum, frdenom)
else
begin
frdenom := -ADigits;
frnum := round(AValue*frdenom);
end;
sfrint := ProcessIntegerFormat(IntToStr(frint), fs, AElements, i,
INT_TOKENS, false, (AElements[i].Token = nftIntTh));
inc(i);
//inc(i);
while (i < numEl) and (AElements[i].Token in TERMINATING_TOKENS) do
begin
sintnumspace := sintnumspace + AElements[i].TextValue;
@ -2751,7 +2765,13 @@ begin
// "normal" fraction
mixed := false;
sfrint := '';
FloatToFraction(AValue, prec, MaxInt, maxdenom, frnum, frdenom);
if ADigits > 0 then
FloatToFraction(AValue, prec, MaxInt, maxdenom, frnum, frdenom)
else
begin
frdenom := -ADigits;
frnum := round(AValue*frdenom);
end;
sintnumspace := '';
end;
@ -2769,6 +2789,7 @@ begin
ssymdenomspace := ssymdenomspace + AElements[i].TextValue;
inc(i);
end;
sfrdenom := ProcessIntegerFormat(IntToStr(frdenom), fs, AElements, i,
FRACDENOM_TOKENS, false, false);
AIndex := i+1;
@ -2894,8 +2915,8 @@ begin
// Check for fraction format
if CheckFraction(section.Elements, el, digits) then
s := ProcessFracFormat(AValue, fs, digits, section.Elements, el)
// Floating-point or integer
else
// Floating-point or integer
s := ProcessFloatFormat(AValue, fs, section.Elements, el);
if (sidx = 0) and isNeg then s := '-' + s;
Result := Result + s;