fpspreadsheet: Reorganize formula recalculation code to achieve more stability against infinite loops.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3477 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-08-13 18:44:38 +00:00
parent 03913876d3
commit 2dd6598e20

View File

@ -513,6 +513,7 @@ type
protected protected
procedure CalcRPNFormula(ACell: PCell); procedure CalcRPNFormula(ACell: PCell);
function CellUsedInFormula(ARow, ACol: Cardinal): Boolean;
procedure ChangedCell(ARow, ACol: Cardinal); procedure ChangedCell(ARow, ACol: Cardinal);
procedure ChangedFont(ARow, ACol: Cardinal); procedure ChangedFont(ARow, ACol: Cardinal);
@ -678,7 +679,6 @@ type
{ Formulas } { Formulas }
procedure CalcFormulas; procedure CalcFormulas;
function CellUsedInFormula(ARow, ACol: Cardinal): Boolean;
{ Data manipulation methods - For Cells } { Data manipulation methods - For Cells }
procedure CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal; AFromWorksheet: TsWorksheet); procedure CopyCell(AFromRow, AFromCol, AToRow, AToCol: Cardinal; AFromWorksheet: TsWorksheet);
@ -1728,6 +1728,10 @@ procedure TsWorksheet.CalcFormulas;
var var
node: TAVLTreeNode; node: TAVLTreeNode;
begin begin
// prevent infinite loop due to triggering of formula calculation whenever
// a cell changes during execution of CalcFormulas.
FWorkbook.FCalculating := true;
try
// Step 1 - mark all formula cells as "not calculated" // Step 1 - mark all formula cells as "not calculated"
node := FCells.FindLowest; node := FCells.FindLowest;
while Assigned(node) do begin while Assigned(node) do begin
@ -1742,6 +1746,9 @@ begin
CalcFormulaCallback(Node.Data, nil); CalcFormulaCallback(Node.Data, nil);
node := FCells.FindSuccessor(node); node := FCells.FindSuccessor(node);
end; end;
finally
FWorkbook.FCalculating := false;
end;
end; end;
{@@ {@@
@ -1907,17 +1914,13 @@ end;
} }
procedure TsWorksheet.ChangedCell(ARow, ACol: Cardinal); procedure TsWorksheet.ChangedCell(ARow, ACol: Cardinal);
begin begin
if not FWorkbook.FCalculating and (boAutoCalc in FWorkbook.Options) then begin if not FWorkbook.FCalculating and (boAutoCalc in FWorkbook.Options) then
if CellUsedInFormula(ARow, ACol) then begin begin
FWorkbook.FCalculating := true; if CellUsedInFormula(ARow, ACol) then
try
CalcFormulas; CalcFormulas;
finally
FWorkbook.FCalculating := false;
end; end;
end; if Assigned(FOnChangeCell) then
end; FOnChangeCell(Self, ARow, ACol);
if Assigned(FOnChangeCell) then FOnChangeCell(Self, ARow, ACol);
end; end;
{@@ {@@