fpspreadsheet: Fix missing error when cells are moved so that a circular reference formula is created (https://forum.lazarus.freepascal.org/index.php/topic,59137.msg441301.html#msg441301).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8269 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2022-04-27 21:28:44 +00:00
parent 05745e2252
commit 16d631d0cf
3 changed files with 82 additions and 5 deletions

View File

@ -2274,9 +2274,12 @@ end;
procedure TsWorksheet.MoveCell(ACell: PCell; AToRow, AToCol: Cardinal);
var
fromRow, fromCol: Cardinal;
destCell: PCell;
sheet: TsWorksheet;
i: Integer;
formula: String;
formula: PsFormula;
formulaStr: String;
srcHasFormula: Boolean;
begin
if ACell = nil then
exit;
@ -2294,12 +2297,12 @@ begin
// location. This is different from copying a formula.
// --> We must prevent CopyCell from adjusting the formula
// --> Erase the formula temporarily.
formula := ReadFormula(ACell);
formulaStr := ReadFormula(ACell);
DeleteFormula(ACell);
CopyCell(fromRow, fromCol, AToRow, AToCol);
// Restore the old formula which points to the old location.
if formula <> '' then
WriteFormula(AToRow, AToCol, formula);
if formulaStr <> '' then
WriteFormula(AToRow, AToCol, formulaStr);
// Fix formula references to this cell
for i := 0 to FWorkbook.GetWorksheetcount-1 do begin
@ -2307,6 +2310,11 @@ begin
sheet.Formulas.FixReferenceToMovedCell(ACell, AToRow, AToCol, self);
end;
// Mark destination cell to contain a formula (if applicable).
destCell := FindCell(AToRow, AToCol);
formula := Formulas.FindFormula(destCell);
UseFormulaInCell(destCell, formula);
// Delete cell at old location
DeleteCell(ACell);

View File

@ -22,6 +22,7 @@ type
protected
procedure Test_MoveCell(ATestKind: Integer);
procedure Test_MoveCell_CircRef(ATestKind: Integer);
published
procedure Test_MoveCell_Value;
@ -32,6 +33,9 @@ type
procedure Test_MoveCell_Formula_ABS;
procedure Test_MoveCell_FormulaRef_REL;
procedure Test_MoveCell_FormulaRef_ABS;
procedure Test_MoveCell_FormulaToValue;
procedure Test_MoveCell_ValueToFormula;
end;
implementation
@ -185,6 +189,68 @@ begin
Test_MoveCell(8);
end;
{==============================================================================}
{ In the following test an occupied cell is moved to a different location
such that a circular reference is created.
ATestKind = 1: value cell is moved to formula cell which points to value cell
2: formula cell is moved to cell to which it points. }
procedure TSpreadMoveTests.Test_MoveCell_CircRef(ATestKind: Integer);
const
VALUE_CELL_ROW = 0;
VALUE_CELL_COL = 0;
FORMULA_CELL_ROW = 11;
FORMULA_CELL_COL = 6;
var
worksheet: TsWorksheet;
workbook: TsWorkbook;
value_cell: PCell = nil;
formula_cell: PCell = nil;
dest_cell: PCell = nil;
begin
workbook := TsWorkbook.Create;
try
workbook.Options := workbook.Options + [boAutoCalc];
worksheet := workBook.AddWorksheet(MoveTestSheet);
// Prepare the worksheet in which a cell is moved.
// The value cell is A1, the formula cell is B2 and it points to A1
value_cell := worksheet.WriteText(VALUE_CELL_ROW, VALUE_CELL_COL, 'abc'); // A1
formula_cell := worksheet.WriteFormula(FORMULA_CELL_ROW, FORMULA_CELL_COL, 'A1');
// Move the cell
try
case ATestKind of
1: begin
worksheet.MoveCell(value_cell, FORMULA_CELL_ROW, FORMULA_CELL_COL);
dest_cell := worksheet.FindCell(FORMULA_CELL_ROW, FORMULA_CELL_COL);
end;
2: begin
worksheet.MoveCell(formula_cell, VALUE_CELL_ROW, VALUE_CELL_COL);
dest_cell := worksheet.FindCell(VALUE_CELL_ROW, VALUE_CELL_COL);
end;
end;
except
end;
// In each case, the destination cell should contain a #REF! error
CheckEquals(true, dest_cell^.ErrorValue = errIllegalRef, 'Circular reference not detected.');
finally
workbook.Free;
end;
end;
procedure TSpreadMoveTests.Test_MoveCell_FormulaToValue;
begin
Test_MoveCell_CircRef(1);
end;
procedure TSpreadMoveTests.Test_MoveCell_ValueToFormula;
begin
Test_MoveCell_CircRef(2);
end;
initialization
RegisterTest(TSpreadMoveTests);

View File

@ -233,7 +233,7 @@
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions Count="7">
<Exceptions Count="8">
<Item1>
<Name Value="EAbort"/>
<Enabled Value="False"/>
@ -259,6 +259,9 @@
<Item7>
<Name Value="EFPSpreadsheetReader"/>
</Item7>
<Item8>
<Name Value="ECalcEngine"/>
</Item8>
</Exceptions>
</Debugging>
</CONFIG>