You've already forked lazarus-ccr
fpspreadsheet: Some bug fixes related with inserting/deleting rows through merged cells/shared formula blocks. Still buggy...
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3578 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -1956,7 +1956,6 @@ procedure TsWorksheet.DeleteColCallback(data, arg: Pointer);
|
|||||||
var
|
var
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
col: PtrInt;
|
col: PtrInt;
|
||||||
fe: TsFormulaElement;
|
|
||||||
formula: TsRPNFormula;
|
formula: TsRPNFormula;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
@ -1977,26 +1976,25 @@ begin
|
|||||||
// (2) update cell addresses affected by the deletion of the column
|
// (2) update cell addresses affected by the deletion of the column
|
||||||
for i:=0 to High(formula) do
|
for i:=0 to High(formula) do
|
||||||
begin
|
begin
|
||||||
fe := formula[i]; // "fe" means "formula element"
|
if (formula[i].ElementKind in [fekCell, fekCellRef, fekCellRange]) then
|
||||||
if (fe.ElementKind in [fekCell, fekCellRef, fekCellRange]) then
|
|
||||||
begin
|
begin
|
||||||
if fe.Col = col then
|
if formula[i].Col = col then
|
||||||
begin
|
begin
|
||||||
fe.ElementKind := fekErr;
|
formula[i].ElementKind := fekErr;
|
||||||
fe.IntValue := ord(errIllegalRef);
|
formula[i].IntValue := ord(errIllegalRef);
|
||||||
end else
|
end else
|
||||||
if fe.Col > col then
|
if formula[i].Col > col then
|
||||||
dec(fe.Col);
|
dec(formula[i].Col);
|
||||||
if (fe.ElementKind = fekCellRange) then
|
if (formula[i].ElementKind = fekCellRange) then
|
||||||
begin
|
begin
|
||||||
if (fe.Col2 = col) then
|
if (formula[i].Col2 = col) then
|
||||||
begin
|
begin
|
||||||
fe.ElementKind := fekErr;
|
formula[i].ElementKind := fekErr;
|
||||||
fe.IntValue := ord(errIllegalRef);
|
formula[i].IntValue := ord(errIllegalRef);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if (fe.Col2 > col) then
|
if (formula[i].Col2 > col) then
|
||||||
dec(fe.Col2);
|
dec(formula[i].Col2);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -2011,7 +2009,6 @@ procedure TsWorksheet.DeleteRowCallback(data, arg: Pointer);
|
|||||||
var
|
var
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
row: PtrInt;
|
row: PtrInt;
|
||||||
fe: TsFormulaElement;
|
|
||||||
formula: TsRPNFormula;
|
formula: TsRPNFormula;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
@ -2032,26 +2029,25 @@ begin
|
|||||||
// (2) update cell addresses affected by the deletion of the column
|
// (2) update cell addresses affected by the deletion of the column
|
||||||
for i:=0 to High(formula) do
|
for i:=0 to High(formula) do
|
||||||
begin
|
begin
|
||||||
fe := formula[i]; // "fe" means "formula element"
|
if (formula[i].ElementKind in [fekCell, fekCellRef, fekCellRange]) then
|
||||||
if (fe.ElementKind in [fekCell, fekCellRef, fekCellRange]) then
|
|
||||||
begin
|
begin
|
||||||
if fe.Row = row then
|
if formula[i].Row = row then
|
||||||
begin
|
begin
|
||||||
fe.ElementKind := fekErr;
|
formula[i].ElementKind := fekErr;
|
||||||
fe.IntValue := ord(errIllegalRef);
|
formula[i].IntValue := ord(errIllegalRef);
|
||||||
end else
|
end else
|
||||||
if fe.Row > row then
|
if formula[i].Row > row then
|
||||||
dec(fe.Row);
|
dec(formula[i].Row);
|
||||||
if (fe.ElementKind = fekCellRange) then
|
if (formula[i].ElementKind = fekCellRange) then
|
||||||
begin
|
begin
|
||||||
if (fe.Row2 = row) then
|
if (formula[i].Row2 = row) then
|
||||||
begin
|
begin
|
||||||
fe.ElementKind := fekErr;
|
formula[i].ElementKind := fekErr;
|
||||||
fe.IntValue := ord(errIllegalRef);
|
formula[i].IntValue := ord(errIllegalRef);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if (fe.Row2 > row) then
|
if (formula[i].Row2 > row) then
|
||||||
dec(fe.Row2);
|
dec(formula[i].Row2);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -5022,7 +5018,6 @@ procedure TsWorksheet.InsertColCallback(data, arg: Pointer);
|
|||||||
var
|
var
|
||||||
cell: PCell;
|
cell: PCell;
|
||||||
col: PtrInt;
|
col: PtrInt;
|
||||||
fe: TsFormulaElement;
|
|
||||||
formula: TsRPNFormula;
|
formula: TsRPNFormula;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
@ -5038,33 +5033,23 @@ begin
|
|||||||
// Update formulas
|
// Update formulas
|
||||||
if HasFormula(cell) then
|
if HasFormula(cell) then
|
||||||
begin
|
begin
|
||||||
{
|
// (1) create an rpn formula
|
||||||
if cell^.SharedFormulaBase <> cell then
|
formula := BuildRPNFormula(cell);
|
||||||
|
// (2) update cell addresses affected by the insertion of a column
|
||||||
|
for i:=0 to Length(formula)-1 do
|
||||||
begin
|
begin
|
||||||
newCell := GetCell(cell^.Row, col);
|
case formula[i].ElementKind of
|
||||||
newCell^.SharedFormulaBase := cell^.SharedFormulaBasse;
|
fekCell, fekCellRef:
|
||||||
end else
|
if formula[i].Col >= col then inc(formula[i].Col);
|
||||||
}
|
fekCellRange:
|
||||||
begin
|
begin
|
||||||
// (1) create an rpn formula
|
if formula[i].Col >= col then inc(formula[i].Col);
|
||||||
formula := BuildRPNFormula(cell);
|
if formula[i].Col2 >= col then inc(formula[i].Col2);
|
||||||
// (2) update cell addresses affected by the insertion of a column
|
end;
|
||||||
for i:=0 to Length(formula)-1 do
|
|
||||||
begin
|
|
||||||
fe := Formula[i]; // "fe" means "formula element"
|
|
||||||
case fe.ElementKind of
|
|
||||||
fekCell, fekCellRef:
|
|
||||||
if fe.Col >= col then inc(fe.Col);
|
|
||||||
fekCellRange:
|
|
||||||
begin
|
|
||||||
if fe.Col >= col then inc(fe.Col);
|
|
||||||
if fe.Col2 >= col then inc(fe.Col2);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
// (3) convert rpn formula back to string formula
|
|
||||||
cell^.FormulaValue := ConvertRPNFormulaToStringFormula(formula);
|
|
||||||
end;
|
end;
|
||||||
|
// (3) convert rpn formula back to string formula
|
||||||
|
cell^.FormulaValue := ConvertRPNFormulaToStringFormula(formula);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -5261,6 +5246,46 @@ begin
|
|||||||
cellnode := FCells.FindSuccessor(cellnode);
|
cellnode := FCells.FindSuccessor(cellnode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Fix merged cells and shared formulas: If the inserted column runs through a
|
||||||
|
// block of merged cells or a shared formula the block is cut into two pieces.
|
||||||
|
// Here we fill the gap with dummy cells and set their MergeBase / SharedFormulaBase
|
||||||
|
// correctly.
|
||||||
|
if ACol > 0 then
|
||||||
|
begin
|
||||||
|
c := ACol - 1;
|
||||||
|
// Seek along the column immediately to the left of the inserted column
|
||||||
|
for r := 0 to GetLastOccupiedRowIndex do
|
||||||
|
begin
|
||||||
|
cell := FindCell(r, c);
|
||||||
|
if not Assigned(cell) then
|
||||||
|
continue;
|
||||||
|
// A merged cell block is found
|
||||||
|
if IsMerged(cell) then
|
||||||
|
begin
|
||||||
|
// Does it extend beyond the newly inserted column?
|
||||||
|
nextcell := FindCell(r, ACol+1);
|
||||||
|
if Assigned(nextcell) and (nextcell^.MergeBase = cell^.MergeBase) then
|
||||||
|
begin
|
||||||
|
// Yes: we add a cell into the gap row and merge it with the others.
|
||||||
|
gapcell := GetCell(r, ACol);
|
||||||
|
gapcell^.Mergebase := cell^.MergeBase;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
// A shared formula block is found
|
||||||
|
if cell^.SharedFormulaBase <> nil then begin
|
||||||
|
// Does it extend beyond the newly inserted column?
|
||||||
|
nextcell := FindCell(r, ACol+1);
|
||||||
|
if Assigned(nextcell) and (nextcell^.SharedFormulaBase = cell^.SharedFormulaBase) then
|
||||||
|
begin
|
||||||
|
// Yes - we add a cell into the gap and share the formula of the base
|
||||||
|
gapcell := GetCell(r, ACol);
|
||||||
|
gapcell^.SharedFormulaBase := cell^.SharedFormulaBase;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
(*
|
||||||
// Fix merged cells: If the inserted column runs through a block of merged
|
// Fix merged cells: If the inserted column runs through a block of merged
|
||||||
// cells the block is cut into two pieces. Here we fill the gap with dummy
|
// cells the block is cut into two pieces. Here we fill the gap with dummy
|
||||||
// cells and set their MergeBase correctly.
|
// cells and set their MergeBase correctly.
|
||||||
@ -5280,6 +5305,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
*)
|
||||||
|
|
||||||
// Update column index of column records
|
// Update column index of column records
|
||||||
for i:=0 to FCols.Count-1 do begin
|
for i:=0 to FCols.Count-1 do begin
|
||||||
@ -5298,7 +5324,6 @@ var
|
|||||||
cell: PCell;
|
cell: PCell;
|
||||||
row: PtrInt;
|
row: PtrInt;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
fe: TsFormulaElement;
|
|
||||||
formula: TsRPNFormula;
|
formula: TsRPNFormula;
|
||||||
begin
|
begin
|
||||||
row := PtrInt(arg);
|
row := PtrInt(arg);
|
||||||
@ -5315,14 +5340,13 @@ begin
|
|||||||
formula := BuildRPNFormula(cell);
|
formula := BuildRPNFormula(cell);
|
||||||
// (2) update cell addresses affected by the insertion of a column
|
// (2) update cell addresses affected by the insertion of a column
|
||||||
for i:=0 to Length(formula)-1 do begin
|
for i:=0 to Length(formula)-1 do begin
|
||||||
fe := formula[i]; // "fe" means "formula element"
|
case formula[i].ElementKind of
|
||||||
case fe.ElementKind of
|
|
||||||
fekCell, fekCellRef:
|
fekCell, fekCellRef:
|
||||||
if fe.Row >= row then inc(fe.Row);
|
if formula[i].Row >= row then inc(formula[i].Row);
|
||||||
fekCellRange:
|
fekCellRange:
|
||||||
begin
|
begin
|
||||||
if fe.Row >= row then inc(fe.Row);
|
if formula[i].Row >= row then inc(formula[i].Row);
|
||||||
if fe.Row2 >= row then inc(fe.Row2);
|
if formula[i].Row2 >= row then inc(formula[i].Row2);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -5343,7 +5367,7 @@ var
|
|||||||
row: PRow;
|
row: PRow;
|
||||||
cellnode: TAVLTreeNode;
|
cellnode: TAVLTreeNode;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
r, c, r1, c1, r2, c2: Cardinal;
|
r, c, cc, r1, c1, r2, c2: Cardinal;
|
||||||
cell, nextcell, gapcell: PCell;
|
cell, nextcell, gapcell: PCell;
|
||||||
begin
|
begin
|
||||||
// Update row index of cell records
|
// Update row index of cell records
|
||||||
@ -5353,25 +5377,44 @@ begin
|
|||||||
cellnode := FCells.FindSuccessor(cellnode);
|
cellnode := FCells.FindSuccessor(cellnode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Fix merged cells: If the inserted row runs through a block of merged
|
// Fix merged cells and shared formulas: If the inserted row runs through a
|
||||||
// cells the block is cut into two pieces. Here we fill the gap with dummy
|
// block of merged cells or a shared formula the block is cut into two pieces.
|
||||||
// cells and set their MergeBase correctly.
|
// Here we fill the gap with dummy cells and set their MergeBase / SharedFormulaBase
|
||||||
for r := 0 to GetLastRowIndex do
|
// correctly.
|
||||||
for c := 0 to GetLastColIndex do
|
if ARow > 0 then
|
||||||
|
begin
|
||||||
|
r := ARow - 1;
|
||||||
|
// Seek along the row immediately above the inserted row
|
||||||
|
for c := 0 to GetLastOccupiedColIndex do
|
||||||
begin
|
begin
|
||||||
cell := FindCell(r, c);
|
cell := FindCell(r, c);
|
||||||
if IsMergeBase(cell) then begin
|
if not Assigned(cell) then
|
||||||
FindMergedRange(cell, r1, c1, r2, c2);
|
continue;
|
||||||
if ARow = r2 + 1 then begin
|
// A merged cell block is found
|
||||||
nextcell := FindCell(ARow + 1, c);
|
if IsMerged(cell) then
|
||||||
if Assigned(nextcell) and (nextcell^.MergeBase = cell) then
|
begin
|
||||||
begin
|
// Does it extend beyond the newly inserted row?
|
||||||
gapcell := GetCell(ARow, c);
|
nextcell := FindCell(ARow+1, c);
|
||||||
gapcell^.MergeBase := cell;
|
if Assigned(nextcell) and (nextcell^.MergeBase = cell^.MergeBase) then
|
||||||
end;
|
begin
|
||||||
|
// Yes: we add a cell into the gap row and merge it with the others.
|
||||||
|
gapcell := GetCell(ARow, c);
|
||||||
|
gapcell^.Mergebase := cell^.MergeBase;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
// A shared formula block is found
|
||||||
|
if cell^.SharedFormulaBase <> nil then begin
|
||||||
|
// Does it extend beyond the newly inserted row?
|
||||||
|
nextcell := FindCell(ARow+1, c);
|
||||||
|
if Assigned(nextcell) and (nextcell^.SharedFormulaBase = cell^.SharedFormulaBase) then
|
||||||
|
begin
|
||||||
|
// Yes - we add a cell into the gap and share the formula of the base
|
||||||
|
gapcell := GetCell(ARow, c);
|
||||||
|
gapcell^.SharedFormulaBase := cell^.SharedFormulaBase;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
// Update row index of row records
|
// Update row index of row records
|
||||||
for i:=0 to FRows.Count-1 do begin
|
for i:=0 to FRows.Count-1 do begin
|
||||||
|
Reference in New Issue
Block a user