diff --git a/components/fpspreadsheet/fpsexprparser.pas b/components/fpspreadsheet/fpsexprparser.pas
index 9b7afa542..779e4c9ac 100644
--- a/components/fpspreadsheet/fpsexprparser.pas
+++ b/components/fpspreadsheet/fpsexprparser.pas
@@ -3956,86 +3956,117 @@ var
cell: PCell;
begin
Result := 0;
- if Arg.ResultType = rtInteger then
- result := Arg.ResInteger
- else
- if Arg.ResultType = rtFloat then
- result := trunc(Arg.ResFloat)
- else
- if Arg.ResultType = rtDateTime then
- result := trunc(Arg.ResDateTime)
- else
- if (Arg.ResultType = rtCell) then
- begin
- cell := ArgToCell(Arg);
- if Assigned(cell) and (cell^.ContentType = cctNumber) then
- result := trunc(cell^.NumberValue);
+ case Arg.ResultType of
+ rtInteger : result := Arg.ResInteger;
+ rtFloat : result := trunc(Arg.ResFloat);
+ rtDateTime : result := trunc(Arg.ResDateTime);
+ rtBoolean : if Arg.ResBoolean then Result := 1 else Result := 0;
+ rtString : if not TryStrToInt(Arg.ResString, Result) then Result := 0;
+ rtCell : begin
+ cell := ArgToCell(Arg);
+ if Assigned(cell) then
+ case cell^.ContentType of
+ cctNumber : result := trunc(cell^.NumberValue);
+ cctDateTime : result := trunc(cell^.DateTimeValue);
+ cctBool : if cell^.BoolValue then result := 1;
+ cctUTF8String: if not TryStrToInt(cell^.UTF8StringValue, result)
+ then Result := 0;
+ end;
+ end;
end;
end;
function ArgToFloat(Arg: TsExpressionResult): TsExprFloat;
-// Utility function for the built-in math functions. Accepts also integers
-// in place of the floating point arguments. To be called in builtins or
-// user-defined callbacks having float results.
+// Utility function for the built-in math functions. Accepts also integers and
+// other data types in place of floating point arguments. To be called in
+// builtins or user-defined callbacks having float results or arguments.
var
cell: PCell;
+ s: String;
+ fs: TFormatSettings;
begin
Result := 0.0;
- if Arg.ResultType = rtInteger then
- result := Arg.ResInteger
- else
- if Arg.ResultType = rtDateTime then
- result := Arg.ResDateTime
- else
- if Arg.ResultType = rtFloat then
- result := Arg.ResFloat
- else
- if (Arg.ResultType = rtCell) then
- begin
- cell := ArgToCell(Arg);
- if Assigned(cell) then
- case cell^.ContentType of
- cctNumber : Result := cell^.NumberValue;
- cctDateTime : Result := cell^.DateTimeValue;
- end;
+ case Arg.ResultType of
+ rtInteger : result := Arg.ResInteger;
+ rtDateTime : result := Arg.ResDateTime;
+ rtFloat : result := Arg.ResFloat;
+ rtBoolean : if Arg.ResBoolean then Result := 1.0 else Result := 0.0;
+ rtString : if not TryStrToFloat(Arg.ResString, Result) then Result := 0.0;
+ rtCell : begin
+ cell := ArgToCell(Arg);
+ if Assigned(cell) then
+ case cell^.ContentType of
+ cctNumber : Result := cell^.NumberValue;
+ cctDateTime : Result := cell^.DateTimeValue;
+ cctBool : if cell^.BoolValue then result := 1.0;
+ cctUTF8String: begin
+ fs := Arg.Worksheet.Workbook.FormatSettings;
+ s := cell^.UTF8StringValue;
+ if not TryStrToFloat(s, result, fs) then
+ result := 0.0;
+ end;
+ end;
+ end;
end;
end;
function ArgToDateTime(Arg: TsExpressionResult): TDateTime;
var
cell: PCell;
+ fs: TFormatSettings;
begin
Result := 0.0;
- if Arg.ResultType = rtDateTime then
- result := Arg.ResDateTime
- else
- if Arg.ResultType = rtInteger then
- Result := Arg.ResInteger
- else
- if Arg.ResultType = rtFloat then
- Result := Arg.ResFloat
- else
- if (Arg.ResultType = rtCell) then
- begin
- cell := ArgToCell(Arg);
- if Assigned(cell) and (cell^.ContentType = cctDateTime) then
- Result := cell^.DateTimeValue;
+ case Arg.ResultType of
+ rtDateTime : result := Arg.ResDateTime;
+ rtInteger : Result := Arg.ResInteger;
+ rtFloat : Result := Arg.ResFloat;
+ rtBoolean : if Arg.ResBoolean then Result := 1.0;
+ rtString : begin
+ fs := Arg.Worksheet.Workbook.FormatSettings;
+ if not TryStrToDateTime(Arg.ResString, Result) then
+ Result := 1.0;
+ end;
+ rtCell : begin
+ cell := ArgToCell(Arg);
+ if Assigned(cell) then
+ if (cell^.ContentType = cctDateTime) then
+ Result := cell^.DateTimeValue;
+ end;
end;
end;
function ArgToString(Arg: TsExpressionResult): String;
+// The Office applications are very fuzzy about data types...
var
cell: PCell;
+ fs: TFormatSettings;
+ dt: TDateTime;
begin
Result := '';
case Arg.ResultType of
rtString : result := Arg.ResString;
rtInteger : Result := IntToStr(Arg.ResInteger);
rtFloat : Result := FloatToStr(Arg.ResFloat);
+ rtBoolean : if Arg.ResBoolean then Result := '1' else Result := '0';
rtCell : begin
cell := ArgToCell(Arg);
- if Assigned(cell) and (cell^.ContentType = cctUTF8String) then
- Result := cell^.UTF8Stringvalue;
+ if Assigned(cell) then
+ case cell^.ContentType of
+ cctUTF8String : Result := cell^.UTF8Stringvalue;
+ cctNumber : Result := Format('%g', [cell^.NumberValue]);
+ cctBool : if cell^.BoolValue then Result := '1' else Result := '0';
+ cctDateTime : begin
+ fs := Arg.Worksheet.Workbook.FormatSettings;
+ dt := cell^.DateTimeValue;
+ if frac(dt) = 0.0 then
+ Result := FormatDateTime(fs.LongTimeFormat, dt, fs)
+ else
+ if trunc(dt) = 0 then
+ Result := FormatDateTime(fs.ShortDateFormat, dt, fs)
+ else
+ Result := FormatDateTime('cc', dt, fs);
+ end;
+ end;
end;
end;
end;
@@ -4070,7 +4101,7 @@ begin
end;
end
else
- if (arg.ResultType in [rtInteger, rtFloat, rtDateTime, rtCell]) then
+ if (arg.ResultType in [rtInteger, rtFloat, rtDateTime, rtCell, rtBoolean]) then
begin
AData[n] := ArgToFloat(arg);
inc(n);
diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas
index 9d00327b6..6ed34838a 100755
--- a/components/fpspreadsheet/fpsopendocument.pas
+++ b/components/fpspreadsheet/fpsopendocument.pas
@@ -1230,9 +1230,12 @@ begin
end;
// Read formula results
- // ... number value
valueType := GetAttrValue(ACellNode, 'office:value-type');
valueStr := GetAttrValue(ACellNode, 'office:value');
+ // ODS wants a 0 in the NumberValue field in case of an error. If there is
+ // no error, this value will be corrected below.
+ cell^.NumberValue := 0.0;
+ // (a) number value
if (valueType = 'float') then begin
if UpperCase(valueStr) = '1.#INF' then
FWorksheet.WriteNumber(cell, 1.0/0.0)
@@ -1253,12 +1256,12 @@ begin
end;
end;
end else
- // Date/time value
+ // (b) Date/time value
if (valueType = 'date') or (valueType = 'time') then begin
floatValue := ExtractDateTimeFromNode(ACellNode, cell^.NumberFormat, cell^.NumberFormatStr);
FWorkSheet.WriteDateTime(cell, floatValue);
end else
- // text
+ // (c) text
if (valueType = 'string') then begin
node := ACellNode.FindNode('text:p');
if (node <> nil) and (node.FirstChild <> nil) then begin
@@ -1266,7 +1269,7 @@ begin
FWorksheet.WriteUTF8Text(cell, valueStr);
end;
end else
- // Text
+ // (e) Text
FWorksheet.WriteUTF8Text(cell, valueStr);
if FIsVirtualMode then
@@ -3604,6 +3607,7 @@ var
formula: String;
valuetype: String;
value: string;
+ valueStr: String;
begin
Unused(AStream, ARow, ACol);
@@ -3623,6 +3627,7 @@ begin
parser.Free;
end;
+ valueStr := '';
case ACell^.ContentType of
cctNumber:
begin
@@ -3647,6 +3652,7 @@ begin
begin
valuetype := 'string';
value := 'office:string-value="' + ACell^.UTF8StringValue +'"';
+ valueStr := '' + ACell^.UTF8StringValue + '';
end;
cctBool:
begin
@@ -3655,8 +3661,10 @@ begin
end;
cctError:
begin
- valuetype := 'error';
- value := 'office:value="' + GetErrorValueStr(ACell^.ErrorValue) + '"';
+ // Strange: but in case of an error, Open/LibreOffice always writes a
+ // float value 0 to the cell
+ valuetype := 'float';
+ value := 'office:value="0"';
end;
end;
@@ -3668,10 +3676,9 @@ begin
if ACell^.CalcState=csCalculated then
AppendToStream(AStream, Format(
'' +
- // '%s'+
+ valueStr +
'', [
formula, valuetype, value, lStyle
- //value
]))
else
AppendToStream(AStream, Format(
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index 251664efc..f32a86606 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -48,10 +48,12 @@
+
+
@@ -61,7 +63,6 @@
-
@@ -71,6 +72,7 @@
+
@@ -80,6 +82,7 @@
+
@@ -96,7 +99,6 @@
-
@@ -110,10 +112,12 @@
+
+
diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
index 7c4eaff1c..d1d287513 100644
--- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
+++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc
@@ -220,7 +220,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
MyWorksheet.WriteErrorValue(Row, 2, errDivideByZero);
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errDivideByZero);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errDivideByZero);
// Division of cell values
inc(Row);
@@ -956,9 +959,12 @@
RPNFunc('ACOS', nil))))
else
MyWorksheet.WriteFormula(Row, 1, formula);
+ MyWorksheet.WriteErrorValue(Row, 2, errOverflow);;
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverFlow);
- MyWorksheet.WriteErrorValue(Row, 2, errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverFlow);
// ARCCOSH - valid result
inc(Row);
@@ -985,9 +991,12 @@
RPNFunc('ACOSH', nil))))
else
MyWorksheet.WriteFormula(Row, 1, formula);
- SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverFlow);
MyWorksheet.WriteErrorValue(Row, 2, errOverflow);
+ SetLength(sollValues, Row+1);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverFlow);
// ASIN
inc(Row);
@@ -1014,9 +1023,12 @@
RPNFunc('ASIN', nil))))
else
Myworksheet.WriteFormula(Row, 1, formula);
- SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverFlow);
MyWorksheet.WriteErrorValue(Row, 2, errOverflow);
+ SetLength(sollValues, Row+1);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverFlow);
// ARCSINH
inc(Row);
@@ -1073,9 +1085,12 @@
RPNFunc('ATANH', nil))))
else
myWorksheet.WriteFormula(Row, 1, formula);
- SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverFlow);
MyWorksheet.WriteErrorValue(Row, 2, errOverFlow);
+ SetLength(sollValues, Row+1);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverFlow);
// CEILING
if AFormat <> sfExcel2 then begin
@@ -1262,7 +1277,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
myWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverflow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
// LN - error due to argument < 0
inc(Row);
@@ -1276,7 +1294,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
MyWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverflow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
// LOG10 - valid result
inc(Row);
@@ -1305,7 +1326,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
myWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverflow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
// LOG10 - error due to argument < 0
inc(Row);
@@ -1319,7 +1343,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
MyWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverFlow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
// LOG - valid result (2 arguments)
inc(Row);
@@ -1352,7 +1379,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
MyWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverflow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
}
// LOG - valid result (1 argument)
@@ -1383,7 +1413,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
MyWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverflow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
// LOG - negative value
inc(Row);
@@ -1398,7 +1431,10 @@
MyWorksheet.WriteFormula(Row, 1, formula);
MyWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverflow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
// LOG of cell
inc(Row);
@@ -1623,7 +1659,10 @@
myWorksheet.WriteFormula(Row, 1, formula);
MyWorksheet.WriteUTF8Text(Row, 2, GetErrorValueStr(errOverflow));
SetLength(sollValues, Row+1);
- sollValues[Row] := ErrorResult(errOverflow);
+ if AFormat = sfOpenDocument then
+ sollValues[Row] := FloatResult(0)
+ else
+ sollValues[Row] := ErrorResult(errOverflow);
// SQRT of cell value
inc(Row);