fpspreadsheet: Implement reading of shared formulas with cell block arguments (see http://forum.lazarus.freepascal.org/index.php/topic,35903.msg238701.html#msg238701)

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5767 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2017-02-20 22:57:23 +00:00
parent 00150366d5
commit 4191575bd1

View File

@@ -603,13 +603,18 @@ type
end; end;
{ TsCellRangeExprNode } { TsCellRangeExprNode }
TsCellRangeIndex = 1..2;
TsCellRangeExprNode = class(TsExprNode) TsCellRangeExprNode = class(TsExprNode)
private private
FWorksheet: TsWorksheet; FWorksheet: TsWorksheet;
FRow1, FRow2: Cardinal; FRow: array[TsCellRangeIndex] of Cardinal;
FCol1, FCol2: Cardinal; FCol: array[TsCellRangeIndex] of Cardinal;
FFlags: TsRelFlags; FFlags: TsRelFlags;
protected protected
function GetCol(AIndex: TsCellRangeIndex): Cardinal;
function GetRow(AIndex: TsCellRangeIndex): Cardinal;
procedure GetNodeValue(out Result: TsExpressionResult); override; procedure GetNodeValue(out Result: TsExpressionResult); override;
public public
constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet; constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
@@ -3548,7 +3553,7 @@ begin
// Nothing to check; // Nothing to check;
end; end;
{ Calculates the row address of the node's cell for various cases: { Calculates the column address of the node's cell for various cases:
(1) Copy mode: (1) Copy mode:
The "DestCell" of the parser is the cell for which the formula is The "DestCell" of the parser is the cell for which the formula is
calculated. The "SourceCell" contains the formula. If the formula contains calculated. The "SourceCell" contains the formula. If the formula contains
@@ -3628,24 +3633,32 @@ constructor TsCellRangeExprNode.Create(AParser: TsExpressionParser;
begin begin
FParser := AParser; FParser := AParser;
FWorksheet := AWorksheet; FWorksheet := AWorksheet;
FRow1 := ARow1; FRow[1] := ARow1;
FCol1 := ACol1; FCol[1] := ACol1;
FRow2 := ARow2; FRow[2] := ARow2;
FCol2 := ACol2; FCol[2] := ACol2;
FFlags := AFlags; FFlags := AFlags;
end; end;
function TsCellRangeExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem; function TsCellRangeExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem;
begin begin
Result := RPNCellRange(FRow1, FCol1, FRow2, FCol2, FFlags, ANext); Result := RPNCellRange(GetRow(1), GetCol(1), GetRow(2), GetCol(2), FFlags, ANext);
end; end;
function TsCellRangeExprNode.AsString: string; function TsCellRangeExprNode.AsString: string;
var
r, c: Array[TsCellRangeIndex] of Cardinal;
i: TsCellRangeIndex;
begin begin
if (FRow1 = FRow2) and (FCol1 = FCol2) then for i in TsCellRangeIndex do
Result := GetCellString(FRow1, FCol1, FFlags) begin
r[i] := GetRow(i);
c[i] := GetCol(i);
end;
if (r[1] = r[2]) and (c[1] = c[2]) then
Result := GetCellString(r[1], r[1], FFlags)
else else
Result := GetCellRangeString(FRow1, FCol1, FRow2, FCol2, FFlags); Result := GetCellRangeString(r[1], c[1], r[2], c[2], FFlags);
end; end;
procedure TsCellRangeExprNode.Check; procedure TsCellRangeExprNode.Check;
@@ -3653,15 +3666,39 @@ begin
// Nothing to check; // Nothing to check;
end; end;
{ Calculates the column address of the node's cell for various cases:
(1) Copy mode:
The "DestCell" of the parser is the cell for which the formula is
calculated. The "SourceCell" contains the formula. If the formula contains
a relative address in the cell node the function calculates the row
address of the cell represented by the node as seen from the DestCell.
If the formula contains an absolute address the function returns the row
address of the SourceCell.
(2) Normal mode:
Returns the "true" row address of the cell assigned to the formula node. }
function TsCellRangeExprNode.GetCol(AIndex: TsCellRangeIndex): Cardinal;
begin
Result := FCol[AIndex];
if FParser.CopyMode and (rfRelCol in FFlags) then
Result := FCol[AIndex] - FParser.FSourceCell^.Col + FParser.FDestCell^.Col;
end;
procedure TsCellRangeExprNode.GetNodeValue(out Result: TsExpressionResult); procedure TsCellRangeExprNode.GetNodeValue(out Result: TsExpressionResult);
var var
r,c: Cardinal; r, c: Array[TsCellRangeIndex] of Cardinal;
rr, cc: Cardinal;
i: TsCellRangeIndex;
cell: PCell; cell: PCell;
begin begin
for r := FRow1 to FRow2 do for i in TsCellRangeIndex do
for c := FCol1 to FCol2 do
begin begin
cell := FWorksheet.FindCell(r, c); r[i] := GetRow(i);
c[i] := GetCol(i);
end;
for rr := r[1] to r[2] do
for cc := c[1] to c[2] do
begin
cell := FWorksheet.FindCell(rr, cc);
if HasFormula(cell) then if HasFormula(cell) then
case FWorksheet.GetCalcState(cell) of case FWorksheet.GetCalcState(cell) of
csNotCalculated: csNotCalculated:
@@ -3672,13 +3709,20 @@ begin
end; end;
Result.ResultType := rtCellRange; Result.ResultType := rtCellRange;
Result.ResCellRange.Row1 := FRow1; Result.ResCellRange.Row1 := r[1];
Result.ResCellRange.Col1 := FCol1; Result.ResCellRange.Col1 := c[1];
Result.ResCellRange.Row2 := FRow2; Result.ResCellRange.Row2 := r[2];
Result.ResCellRange.Col2 := FCol2; Result.ResCellRange.Col2 := c[2];
Result.Worksheet := FWorksheet; Result.Worksheet := FWorksheet;
end; end;
function TsCellRangeExprNode.GetRow(AIndex: TsCellRangeIndex): Cardinal;
begin
Result := FRow[AIndex];
if FParser.CopyMode and (rfRelRow in FFlags) then
Result := FRow[AIndex] - FParser.FSourceCell^.Row + FParser.FDestCell^.Row;
end;
function TsCellRangeExprNode.NodeType: TsResultType; function TsCellRangeExprNode.NodeType: TsResultType;
begin begin
Result := rtCellRange; Result := rtCellRange;