You've already forked lazarus-ccr
fpspreadsheet: MoveCell completely overwrites destination cell. MoveCell with sourcecell=nil erases destination cell. Related unit test cases.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8270 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -1614,6 +1614,7 @@ begin
|
|||||||
// Short-cut for source and destination worksheets
|
// Short-cut for source and destination worksheets
|
||||||
srcSheet := TsWorksheet(AFromcell^.Worksheet);
|
srcSheet := TsWorksheet(AFromcell^.Worksheet);
|
||||||
destSheet := TsWorksheet(AToCell^.Worksheet);
|
destSheet := TsWorksheet(AToCell^.Worksheet);
|
||||||
|
if destSheet = nil then destSheet := srcSheet;
|
||||||
|
|
||||||
// Remember the row and column indexes of the destination cell.
|
// Remember the row and column indexes of the destination cell.
|
||||||
toRow := AToCell^.Row;
|
toRow := AToCell^.Row;
|
||||||
@@ -2279,20 +2280,28 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
formula: PsFormula;
|
formula: PsFormula;
|
||||||
formulaStr: String;
|
formulaStr: String;
|
||||||
srcHasFormula: Boolean;
|
|
||||||
begin
|
begin
|
||||||
if ACell = nil then
|
destCell := FindCell(AToRow, AToCol);
|
||||||
exit;
|
|
||||||
|
|
||||||
// Avoid misplaced notifications during the copy operations when things could
|
// Moving an empty cell should clear the destination cell.
|
||||||
// not yet be in place.
|
if ACell = nil then
|
||||||
|
begin
|
||||||
|
DeleteCell(destCell);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Avoid misplaced notifications during the copy operations when things are
|
||||||
|
// not in place, yet.
|
||||||
FWorkbook.DisableNotifications;
|
FWorkbook.DisableNotifications;
|
||||||
|
|
||||||
// Store old location
|
// Store old location
|
||||||
fromRow := ACell^.Row;
|
fromRow := ACell^.Row;
|
||||||
fromCol := ACell^.Col;
|
fromCol := ACell^.Col;
|
||||||
|
|
||||||
// Copy cell to new location
|
// Clear destination cell
|
||||||
|
EraseCell(destCell);
|
||||||
|
|
||||||
|
// Copy cell to new location (taking care of comments, hyperlinks etc)
|
||||||
// Note: In Excel the formula in a moved cell still points to the initial
|
// Note: In Excel the formula in a moved cell still points to the initial
|
||||||
// location. This is different from copying a formula.
|
// location. This is different from copying a formula.
|
||||||
// --> We must prevent CopyCell from adjusting the formula
|
// --> We must prevent CopyCell from adjusting the formula
|
||||||
@@ -2304,18 +2313,17 @@ begin
|
|||||||
if formulaStr <> '' then
|
if formulaStr <> '' then
|
||||||
WriteFormula(AToRow, AToCol, formulaStr);
|
WriteFormula(AToRow, AToCol, formulaStr);
|
||||||
|
|
||||||
// Fix formula references to this cell
|
// Fix formula references to the source cell (ACell)
|
||||||
for i := 0 to FWorkbook.GetWorksheetcount-1 do begin
|
for i := 0 to FWorkbook.GetWorksheetcount-1 do begin
|
||||||
sheet := FWorkbook.GetWorksheetByIndex(i);
|
sheet := FWorkbook.GetWorksheetByIndex(i);
|
||||||
sheet.Formulas.FixReferenceToMovedCell(ACell, AToRow, AToCol, self);
|
sheet.Formulas.FixReferenceToMovedCell(ACell, AToRow, AToCol, self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Mark destination cell to contain a formula (if applicable).
|
// Mark destination cell to contain a formula (if applicable).
|
||||||
destCell := FindCell(AToRow, AToCol);
|
|
||||||
formula := Formulas.FindFormula(destCell);
|
formula := Formulas.FindFormula(destCell);
|
||||||
UseFormulaInCell(destCell, formula);
|
UseFormulaInCell(destCell, formula);
|
||||||
|
|
||||||
// Delete cell at old location
|
// Delete source cell at old location
|
||||||
DeleteCell(ACell);
|
DeleteCell(ACell);
|
||||||
|
|
||||||
FWorkbook.EnableNotifications;
|
FWorkbook.EnableNotifications;
|
||||||
|
@@ -22,7 +22,6 @@ type
|
|||||||
|
|
||||||
protected
|
protected
|
||||||
procedure Test_MoveCell(ATestKind: Integer);
|
procedure Test_MoveCell(ATestKind: Integer);
|
||||||
procedure Test_MoveCell_CircRef(ATestKind: Integer);
|
|
||||||
|
|
||||||
published
|
published
|
||||||
procedure Test_MoveCell_Value;
|
procedure Test_MoveCell_Value;
|
||||||
@@ -34,8 +33,10 @@ type
|
|||||||
procedure Test_MoveCell_FormulaRef_REL;
|
procedure Test_MoveCell_FormulaRef_REL;
|
||||||
procedure Test_MoveCell_FormulaRef_ABS;
|
procedure Test_MoveCell_FormulaRef_ABS;
|
||||||
|
|
||||||
procedure Test_MoveCell_FormulaToValue;
|
procedure Test_MoveCell_CircRef;
|
||||||
procedure Test_MoveCell_ValueToFormula;
|
procedure Test_MoveCell_OverwriteFormula;
|
||||||
|
procedure Test_MoveCell_EmptyToValue;
|
||||||
|
procedure Test_MoveCell_EmptyToFormula;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -191,20 +192,18 @@ end;
|
|||||||
|
|
||||||
{==============================================================================}
|
{==============================================================================}
|
||||||
|
|
||||||
{ In the following test an occupied cell is moved to a different location
|
{ In the following test an occupied cell with a formula is moved to a location
|
||||||
such that a circular reference is created.
|
referenced by the formula.
|
||||||
ATestKind = 1: value cell is moved to formula cell which points to value cell
|
This must result in a circular reference error. }
|
||||||
2: formula cell is moved to cell to which it points. }
|
procedure TSpreadMoveTests.Test_MoveCell_CircRef;
|
||||||
procedure TSpreadMoveTests.Test_MoveCell_CircRef(ATestKind: Integer);
|
|
||||||
const
|
const
|
||||||
VALUE_CELL_ROW = 0;
|
VALUE_CELL_ROW = 0; // A1
|
||||||
VALUE_CELL_COL = 0;
|
VALUE_CELL_COL = 0;
|
||||||
FORMULA_CELL_ROW = 11;
|
FORMULA_CELL_ROW = 11; // F10
|
||||||
FORMULA_CELL_COL = 6;
|
FORMULA_CELL_COL = 6;
|
||||||
var
|
var
|
||||||
worksheet: TsWorksheet;
|
worksheet: TsWorksheet;
|
||||||
workbook: TsWorkbook;
|
workbook: TsWorkbook;
|
||||||
value_cell: PCell = nil;
|
|
||||||
formula_cell: PCell = nil;
|
formula_cell: PCell = nil;
|
||||||
dest_cell: PCell = nil;
|
dest_cell: PCell = nil;
|
||||||
begin
|
begin
|
||||||
@@ -215,26 +214,18 @@ begin
|
|||||||
worksheet := workBook.AddWorksheet(MoveTestSheet);
|
worksheet := workBook.AddWorksheet(MoveTestSheet);
|
||||||
|
|
||||||
// Prepare the worksheet in which a cell is moved.
|
// Prepare the worksheet in which a cell is moved.
|
||||||
// The value cell is A1, the formula cell is B2 and it points to A1
|
// The value cell is A1, the formula cell is F10 and it points to A1
|
||||||
value_cell := worksheet.WriteText(VALUE_CELL_ROW, VALUE_CELL_COL, 'abc'); // A1
|
worksheet.WriteText(VALUE_CELL_ROW, VALUE_CELL_COL, 'abc'); // A1
|
||||||
formula_cell := worksheet.WriteFormula(FORMULA_CELL_ROW, FORMULA_CELL_COL, 'A1');
|
formula_cell := worksheet.WriteFormula(FORMULA_CELL_ROW, FORMULA_CELL_COL, 'A1');
|
||||||
|
|
||||||
// Move the cell
|
// Move the formula cell to overwrite the value cell
|
||||||
try
|
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);
|
worksheet.MoveCell(formula_cell, VALUE_CELL_ROW, VALUE_CELL_COL);
|
||||||
dest_cell := worksheet.FindCell(VALUE_CELL_ROW, VALUE_CELL_COL);
|
dest_cell := worksheet.FindCell(VALUE_CELL_ROW, VALUE_CELL_COL);
|
||||||
end;
|
|
||||||
end;
|
|
||||||
except
|
except
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// In each case, the destination cell should contain a #REF! error
|
// The destination cell should contain a #REF! error
|
||||||
CheckEquals(true, dest_cell^.ErrorValue = errIllegalRef, 'Circular reference not detected.');
|
CheckEquals(true, dest_cell^.ErrorValue = errIllegalRef, 'Circular reference not detected.');
|
||||||
|
|
||||||
finally
|
finally
|
||||||
@@ -242,14 +233,130 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadMoveTests.Test_MoveCell_FormulaToValue;
|
{ In the following test an occupied cell with a value formula is moved to
|
||||||
|
a location with a formula cell pointing to the moved value cell.
|
||||||
|
This operation must delete the formula after moving. }
|
||||||
|
procedure TSpreadMoveTests.Test_MoveCell_OverwriteFormula;
|
||||||
|
const
|
||||||
|
VALUE_CELL_ROW = 0; // A1
|
||||||
|
VALUE_CELL_COL = 0;
|
||||||
|
FORMULA_CELL_ROW = 11; // F10
|
||||||
|
FORMULA_CELL_COL = 6;
|
||||||
|
var
|
||||||
|
worksheet: TsWorksheet;
|
||||||
|
workbook: TsWorkbook;
|
||||||
|
value_cell: PCell = nil;
|
||||||
|
dest_cell: PCell = nil;
|
||||||
begin
|
begin
|
||||||
Test_MoveCell_CircRef(1);
|
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 F10 and it points to A1
|
||||||
|
value_cell := worksheet.WriteText(VALUE_CELL_ROW, VALUE_CELL_COL, 'abc'); // A1
|
||||||
|
worksheet.WriteFormula(FORMULA_CELL_ROW, FORMULA_CELL_COL, 'A1');
|
||||||
|
|
||||||
|
// Move the value cell to overwrite the formula cell
|
||||||
|
try
|
||||||
|
worksheet.MoveCell(value_cell, FORMULA_CELL_ROW, FORMULA_CELL_COL);
|
||||||
|
dest_cell := worksheet.FindCell(FORMULA_CELL_ROW, FORMULA_CELL_COL);
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
|
||||||
|
// The destination cell should not contain a formula any more.
|
||||||
|
CheckEquals(false, HasFormula(dest_cell), 'Formula has not been removed.');
|
||||||
|
// Check value at destination after moving
|
||||||
|
CheckEquals('abc', worksheet.ReadAsText(dest_cell), 'Moved value mismatch.');
|
||||||
|
// Check value at source after moving
|
||||||
|
CheckEquals('', worksheet.ReadAsText(value_cell), 'Source value mismatch after moving.');
|
||||||
|
|
||||||
|
finally
|
||||||
|
workbook.Free;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSpreadMoveTests.Test_MoveCell_ValueToFormula;
|
{ In the following test an empty cell is moved to a location with a value cell.
|
||||||
|
This operation must delete the value in the destination cell after moving. }
|
||||||
|
procedure TSpreadMoveTests.Test_MoveCell_EmptyToValue;
|
||||||
|
const
|
||||||
|
SOURCE_CELL_ROW = 0; // A1
|
||||||
|
SOURCE_CELL_COL = 0;
|
||||||
|
DEST_CELL_ROW = 2; // C3
|
||||||
|
DEST_CELL_COL = 2;
|
||||||
|
var
|
||||||
|
worksheet: TsWorksheet;
|
||||||
|
workbook: TsWorkbook;
|
||||||
|
src_cell: PCell = nil;
|
||||||
|
dest_cell: PCell = nil;
|
||||||
begin
|
begin
|
||||||
Test_MoveCell_CircRef(2);
|
workbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
workbook.Options := workbook.Options + [boAutoCalc];
|
||||||
|
|
||||||
|
worksheet := workBook.AddWorksheet(MoveTestSheet);
|
||||||
|
|
||||||
|
// Prepare the worksheet in which an empty cell is moved.
|
||||||
|
src_cell := nil; // A1
|
||||||
|
dest_cell := worksheet.WriteText(DEST_CELL_ROW, DEST_CELL_COL, 'abc'); // C3
|
||||||
|
|
||||||
|
// Move the source cell to overwrite the value cell
|
||||||
|
try
|
||||||
|
worksheet.MoveCell(src_cell, DEST_CELL_ROW, DEST_CELL_COL);
|
||||||
|
dest_cell := worksheet.FindCell(DEST_CELL_ROW, DEST_CELL_COL);
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
|
||||||
|
// The destination cell should be empty.
|
||||||
|
CheckEquals(true, dest_cell = nil, 'Destination cell nas not been deleted.');
|
||||||
|
|
||||||
|
finally
|
||||||
|
workbook.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ In the following test an empty cell is moved to a location with a formula cell.
|
||||||
|
This operation must delete the destination cell after moving. In particular,
|
||||||
|
there must not be a formula any more. }
|
||||||
|
procedure TSpreadMoveTests.Test_MoveCell_EmptyToFormula;
|
||||||
|
const
|
||||||
|
SOURCE_CELL_ROW = 0; // A1
|
||||||
|
SOURCE_CELL_COL = 0;
|
||||||
|
DEST_CELL_ROW = 2; // C3
|
||||||
|
DEST_CELL_COL = 2;
|
||||||
|
var
|
||||||
|
worksheet: TsWorksheet;
|
||||||
|
workbook: TsWorkbook;
|
||||||
|
src_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
|
||||||
|
src_cell := nil; // A1
|
||||||
|
dest_cell := worksheet.WriteFormula(DEST_CELL_ROW, DEST_CELL_COL, 'PI()'); // C3
|
||||||
|
|
||||||
|
// Move the empty source cell to overwrite the formula cell
|
||||||
|
try
|
||||||
|
worksheet.MoveCell(src_cell, DEST_CELL_ROW, DEST_CELL_COL);
|
||||||
|
dest_cell := worksheet.FindCell(DEST_CELL_ROW, DEST_CELL_COL);
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
|
||||||
|
// The destination cell should be empty.
|
||||||
|
CheckEquals(false, HasFormula(dest_cell), 'Destination cell still contains a formula.');
|
||||||
|
CheckEquals(true, dest_cell = nil, 'Destination cell has not been deleted.');
|
||||||
|
|
||||||
|
finally
|
||||||
|
workbook.Free;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
Reference in New Issue
Block a user