fpspreadsheet: Fix incorrect handling of cell reference by new forumula INDIRECT(). Add test cases for formula ADDRESS().

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@7862 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2020-11-11 23:43:44 +00:00
parent 02e6f28f3b
commit 95cc2da283
5 changed files with 108 additions and 16 deletions

View File

@ -100,7 +100,8 @@ type
rtFloat : (ResFloat : TsExprFloat);
rtDateTime : (ResDateTime : TDatetime);
rtCell : (ResRow, ResCol : Cardinal;
ResSheetIndex : Integer);
ResSheetIndex : Integer;
ResSheetName : String[32]);
rtCellRange : (ResCellRange : TsCellRange3D);
rtHyperlink : ();
rtString : ();
@ -3936,7 +3937,8 @@ begin
n := Length(FArgumentNodes);
Result := ANext;
for i:=0 to High(FArgumentNodes) do
Result := FArgumentNodes[i].AsRPNItem(Result);
if FArgumentNodes[i] <> nil then
Result := FArgumentNodes[i].AsRPNItem(Result);
Result := RPNFunc(FID.Name, n, Result);
end;
@ -3962,7 +3964,8 @@ var
i : Integer;
begin
for i := 0 to Length(FArgumentParams)-1 do
FArgumentNodes[i].GetNodeValue(FArgumentParams[i]);
if FArgumentNodes[i] <> nil then
FArgumentNodes[i].GetNodeValue(FArgumentParams[i]);
end;
procedure TsFunctionExprNode.Check;
@ -4006,8 +4009,9 @@ function TsFunctionExprNode.Has3DLink: Boolean;
var
i : Integer;
begin
for i := 0 to Length(FArgumentParams)-1 do
if FArgumentNodes[i].Has3DLink then exit(true);
i := Length(FArgumentNodes);
for i := 0 to High(FArgumentParams) do
if (FArgumentNodes[i] <> nil) and FArgumentNodes[i].Has3DLink then exit(true);
Result := false;
end;
@ -4017,7 +4021,8 @@ var
i: Integer;
begin
for i:=0 to High(FArgumentParams) do
FArgumentNodes[i].IterateNodes(AProc, AData1, AData2, MustRebuildFormulas);
if FArgumentNodes[i] <> nil then
FArgumentNodes[i].IterateNodes(AProc, AData1, AData2, MustRebuildFormulas);
end;
@ -4205,7 +4210,18 @@ begin
AResult.ResultType := rtCell;
AResult.ResRow := GetRow;
AResult.ResCol := GetCol;
AResult.Worksheet := GetSheet;
sheet := GetSheet as TsWorksheet;
AResult.Worksheet := sheet;
{
if sheet = FWorksheet then
begin
AResult.ResSheetName := sheet.Name;
AResult.ResSheetIndex := -1;
end else
begin}
AResult.ResSheetname := sheet.Name;
AResult.ResSheetIndex := sheet.Workbook.GetWorkSheetIndex(sheet);
// end;
end;
function TsCellExprNode.GetQuotedSheetName: String;
@ -4795,9 +4811,21 @@ begin
end;
function CellResult(AValue: String): TsExpressionResult;
var
p: Integer;
begin
Result.ResultType := rtCell;
ParseCellString(AValue, Result.ResRow, Result.ResCol);
p := pos('!', AValue);
if p = 0 then
begin
ParseCellString(AValue, Result.ResRow, Result.ResCol);
Result.ResSheetName := '';
end else
begin
Result.ResSheetName := Copy(AValue, 1, p-1);
ParseCellString(Copy(AValue, p+1, MaxInt), Result.ResRow, Result.ResCol);
Result.Worksheet := nil; // this signals that the worksheet needs still to be determiend
end;
end;
function CellResult(ACellRow, ACellCol: Cardinal): TsExpressionResult;

View File

@ -2148,7 +2148,7 @@ begin
end;
A1Dialect := true;
if Length(Args) > 3 then
if (Length(Args) > 3) and (Args[3].ResultType <> rtMissingArg) then
A1Dialect := ArgToBoolean(Args[3]);
sheet := '';
@ -2162,6 +2162,7 @@ begin
if sheet <> '' then resStr := sheet + '!' + resStr;
// Result := CellResult(resStr);
Result := StringResult(resStr);
end;
@ -2211,11 +2212,28 @@ procedure fpsINDIRECT(var Result: TsExpressionResult;
interpreted as an R1C1-style reference.
NOTE: ref_style and mixing of A1 and R1C1 notation is not supported. }
var
sheet: TsWorksheet;
book: TsWorkbook;
addr: String;
begin
Result := ErrorResult(errArgError);
if Length(Args) = 0 then
exit;
Result := Args[0];
if (Args[0].ResultType = rtCell) then begin
if Args[0].ResSheetIndex = -1 then
sheet := TsWorksheet(Args[0].Worksheet)
else
begin
book := TsWorksheet(Args[0].Worksheet).Workbook;
sheet := book.GetWorksheetByIndex(Args[0].ResSheetIndex);
end;
addr := sheet.ReadAsText(Args[0].ResRow, Args[0].ResCol);
Result := CellResult(addr);
Result.Worksheet := sheet;
end else
if (Args[0].ResultType = rtString) then
Result := CellResult(Args[0].ResString);
end;

View File

@ -1370,6 +1370,15 @@ begin
end;
rtBoolean : WriteBoolValue(lCell, res.ResBoolean);
rtCell : begin
if res.Worksheet = nil then
begin
if res.ResSheetName = '' then
res.Worksheet := self
else
res.Worksheet := Workbook.GetWorksheetByName(res.ResSheetName);
end else
if res.ResSheetName <> '' then
res.Worksheet := Workbook.GetWorksheetByName(res.ResSheetname);
lCellRef := (res.Worksheet as TsWorksheet).FindCell(res.ResRow, res.ResCol);
if lCellRef <> nil then
case lCellRef^.ContentType of

View File

@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<Version Value="11"/>
<PathDelim Value="\"/>
<General>
<Flags>
<CompatibilityMode Value="True"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<Title Value="spreadtestgui"/>
<ResourceType Value="res"/>
</General>

View File

@ -3347,9 +3347,48 @@
{------------------------------------------------------------------------------}
{ Lookup / reference functions }
{ Lookup / reference functions }
{------------------------------------------------------------------------------}
{
// ADDRESS
inc(Row);
formula := 'ADDRESS(1,1)';
MyWorksheet.WriteText(Row, 0, formula);
{
if UseRPNFormula then
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(
RPNInteger(1,
RPNInteger(1,
RPNFunc('ADDRESS', nil))))) // ---> does not work...
else
}
MyWorksheet.WriteFormula(Row, 1, formula);
SetLength(sollValues, Row+1);
sollValues[Row] := StringResult('$A$1');
inc(Row);
formula := 'ADDRESS(1,1,4)';
MyWorksheet.WriteText(Row, 0, formula);
MyWorksheet.WriteFormula(Row, 1, formula);
SetLength(sollValues, Row+1);
sollValues[Row] := StringResult('A1');
inc(Row);
formula := 'ADDRESS(1,1,,,"Sheet2")';
MyWorksheet.WriteText(Row, 0, formula);
Myworksheet.WriteFormula(Row, 1, formula);
SetLength(sollValues, Row+1);
sollValues[Row] := StringResult('Sheet2!$A$1');
inc(Row);
formula := 'ADDRESS(1,1,,FALSE,"Sheet2")';
MyWorksheet.WriteText(Row, 0, formula);
Myworksheet.WriteFormula(Row, 1, formula);
SetLength(sollValues, Row+1);
sollValues[Row] := StringResult('Sheet2!R1C1');
{
// COLUMN
MyWorksheet.WriteText(Row, 0, 'COLUMN(A1)');
MyWorksheet.WriteRPNFormula(Row, 1, CreateRPNFormula(