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