diff --git a/components/fpspreadsheet/source/common/fpsexprparser.pas b/components/fpspreadsheet/source/common/fpsexprparser.pas index 82e6c1f0d..ce9b6f540 100644 --- a/components/fpspreadsheet/source/common/fpsexprparser.pas +++ b/components/fpspreadsheet/source/common/fpsexprparser.pas @@ -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; diff --git a/components/fpspreadsheet/source/common/fpsfunc.pas b/components/fpspreadsheet/source/common/fpsfunc.pas index 6d0a7403d..342a66d76 100644 --- a/components/fpspreadsheet/source/common/fpsfunc.pas +++ b/components/fpspreadsheet/source/common/fpsfunc.pas @@ -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; diff --git a/components/fpspreadsheet/source/common/fpspreadsheet.pas b/components/fpspreadsheet/source/common/fpspreadsheet.pas index 23e4c6642..2fef7080d 100644 --- a/components/fpspreadsheet/source/common/fpspreadsheet.pas +++ b/components/fpspreadsheet/source/common/fpspreadsheet.pas @@ -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 diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi index e7b7a70b1..590cda61d 100644 --- a/components/fpspreadsheet/tests/spreadtestgui.lpi +++ b/components/fpspreadsheet/tests/spreadtestgui.lpi @@ -1,13 +1,11 @@ - + - - - + <ResourceType Value="res"/> </General> diff --git a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc index ed7a81cc0..40feb9ef7 100644 --- a/components/fpspreadsheet/tests/testcases_calcrpnformula.inc +++ b/components/fpspreadsheet/tests/testcases_calcrpnformula.inc @@ -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(