fpspreadsheet: Fix 3d formulas not changing when rows/cols are inserted/deleted in referenced sheets.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6454 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-06-04 09:47:08 +00:00
parent 6c19ca21cb
commit 394c8032df
5 changed files with 254 additions and 134 deletions

View File

@ -193,10 +193,10 @@ type
AParsedFormula: TsExpressionParser = nil): PsFormula;
procedure DeleteFormula(ACell: PCell); overload;
procedure DeleteFormula(ARow, ACol: Cardinal); overload;
procedure DeleteRowOrCol(AIndex: Cardinal; IsRow: Boolean);
function FindFormula(ACell: PCell): PsFormula; overload;
function FindFormula(ARow, ACol: Cardinal): PsFormula; overload;
procedure InsertRowOrCol(AIndex: Cardinal; IsRow: Boolean);
procedure FixReferences(AIndex: Cardinal; IsRow, IsDeleting: Boolean;
InSheet: TsBasicWorksheet);
// enumerators
function GetEnumerator: TsFormulaEnumerator;
end;
@ -252,140 +252,209 @@ end;
{ Call-back function for formulas when rows/cols are inserted/deleted }
procedure FixDeletedCol(AExprNode: TsExprNode; AData: Pointer;
procedure FixDeletedCol(AExprNode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
colIndex: Cardinal;
referencedSheet, referencedSheet2: TsBasicWorksheet;
changedSheet: TsBasicWorksheet;
rng: TsCellRange;
begin
colIndex := PtrInt(AData);
colIndex := PtrInt(AData1);
changedSheet := TsBasicWorksheet(AData2);
if AExprNode is TsCellExprNode then
begin
if not TsCellExprNode(AExprNode).Has3dLink then
if TsCellExprNode(AExprNode).Col > colIndex then begin
TsCellExprNode(AExprNode).Col := TsCellexprNode(AExprNode).Col - 1;
MustRebuildFormulas := true;
end else
if TsCellExprNode(AExprNode).Col = colIndex then begin
TsCellExprNode(AExprNode).Error := errIllegalRef;
MustRebuildFormulas := true;
end;
end else
if TsCellExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellExprNode(AExprNode).GetSheet;
if TsCellExprNode(AExprNode).Has3dLink and (referencedSheet <> changedSheet) then
exit;
if TsCellExprNode(AExprNode).Col > colIndex then begin
TsCellExprNode(AExprNode).Col := TsCellExprNode(AExprNode).Col - 1;
MustRebuildFormulas := true;
end else
if TsCellExprNode(AExprNode).col = colIndex then begin
TsCellExprNode(AExprNode).Error := errIllegalRef;
MustRebuildFormulas := true;
end;
end
else
if AExprNode is TsCellRangeExprNode then
begin
if not TsCellRangeExprNode(AExprNode).Has3dLink then begin
rng := TsCellRangeExprNode(AExprNode).Range;
if (rng.Col1 = colIndex) and (rng.Col2 = colIndex) then begin
TsCellRangeExprNode(AExprNode).Error := errIllegalRef;
if TsCellRangeExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellRangeExprNode(AExprNode).GetSheet(1);
referencedSheet2 := TsCellRangeExprNode(AExprNode).GetSheet(2);
if TsCellRangeExprNode(AExprNode).Has3dLink and
(referencedSheet <> changedSheet) and
(referencedSheet2 <> changedSheet)
then
exit;
rng := TsCellRangeExprNode(AExprNode).Range;
if (rng.Col1 = colIndex) and (rng.Col2 = colIndex) then begin
TsCellRangeExprNode(AExprNode).Error := errIllegalRef;
MustRebuildFormulas := true;
end else begin
if rng.Col1 > colIndex then begin
dec(rng.Col1);
MustRebuildFormulas := true;
end else begin
if rng.Col1 > colIndex then begin
dec(rng.Col1);
MustRebuildFormulas := true;
end;
if rng.Col2 >= colIndex then begin
dec(rng.Col2);
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
if rng.Col2 >= colIndex then begin
dec(rng.Col2);
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
end;
end;
procedure FixDeletedRow(AExprNode: TsExprNode; AData: Pointer;
procedure FixDeletedRow(AExprNode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
rowIndex: Cardinal;
rng: TsCellRange;
changedSheet: TsBasicWorksheet;
referencedSheet, referencedSheet2: TsBasicWorksheet;
begin
rowIndex := PtrInt(AData);
rowIndex := PtrInt(AData1);
changedSheet := TsBasicWorksheet(AData2);
if AExprNode is TsCellExprNode then
begin
if not TsCellExprNode(AExprNode).Has3dLink then
if TsCellExprNode(AExprNode).Row > rowIndex then begin
TsCellExprNode(AExprNode).Row := TsCellExprNode(AExprNode).Row - 1;
MustRebuildFormulas := true;
end else
if TsCellExprNode(AExprNode).Row = rowIndex then begin
TsCelLExprNode(AExprNode).Error := errIllegalRef;
MustRebuildFormulas := true;
end;
end else
if TsCellExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellExprNode(AExprNode).GetSheet;
if TsCellExprNode(AExprNode).Has3dLink and (referencedSheet <> changedSheet) then
exit;
if TsCellExprNode(AExprNode).Row > rowIndex then begin
TsCellExprNode(AExprNode).Row := TsCellExprNode(AExprNode).Row - 1;
MustRebuildFormulas := true;
end else
if TsCellExprNode(AExprNode).Row = rowIndex then begin
TsCellExprNode(AExprNode).Error := errIllegalRef;
MustRebuildFormulas := true;
end;
end
else
if AExprNode is TsCellRangeExprNode then
begin
if not TsCellRangeExprNode(AExprNode).Has3dLink then begin
rng := TsCellRangeExprNode(AExprNode).Range;
if (rng.Row1 = rowIndex) and (rng.Row2 = rowIndex) then begin
TsCellRangeExprNode(AExprNode).Error := errIllegalRef;
if TsCellRangeExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellRangeExprNode(AExprNode).GetSheet(1);
referencedSheet2 := TsCellRangeExprNode(AExprNode).GetSheet(2);
if TsCellRangeExprNode(AExprNode).Has3dLink and
(referencedSheet <> changedSheet) and
(referencedSheet2 <> changedSheet)
then
exit;
rng := TsCellRangeExprNode(AExprNode).Range;
if (rng.Row1 = rowIndex) and (rng.Row2 = rowIndex) then begin
TsCellRangeExprNode(AExprNode).Error := errIllegalRef;
MustRebuildFormulas := true;
end else
begin
if rng.Row1 > rowIndex then begin
dec(rng.Row1);
MustRebuildFormulas := true;
end else
begin
if rng.Row1 > rowIndex then begin
dec(rng.Row1);
MustRebuildFormulas := true;
end;
if rng.Row2 >= rowIndex then begin
dec(rng.Row2);
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
if rng.Row2 >= rowIndex then begin
dec(rng.Row2);
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
end;
end;
procedure FixInsertedCol(AExprNode: TsExprNode; AData: Pointer;
procedure FixInsertedCol(AExprNode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
colIndex: Cardinal;
changedSheet: TsBasicWorksheet;
referencedSheet, referencedSheet2: TsBasicWorksheet;
rng: TsCellRange;
begin
colIndex := PtrInt(AData);
colIndex := PtrInt(AData1);
changedSheet := TsBasicWorksheet(AData2);
if AExprNode is TsCellExprNode then
begin
if not TsCellExprNode(AExprNode).Has3dLink then
if TsCellExprNode(AExprNode).Col >= colIndex then begin
TsCellExprNode(AExprNode).Col := TsCellexprNode(AExprNode).Col + 1;
MustRebuildFormulas := true;
end;
if TsCellExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellExprNode(AExprNode).GetSheet;
if TsCellExprNode(AExprNode).Has3dLink and (referencedSheet <> changedSheet) then
exit;
if TsCellExprNode(AExprNode).Col >= colIndex then begin
TsCellExprNode(AExprNode).Col := TsCellExprNode(AExprNode).Col + 1;
MustRebuildFormulas := true;
end;
end else
if AExprNode is TsCellRangeExprNode then
begin
if not TsCellRangeExprNode(AExprNode).Has3dLink then begin
rng := TsCellRangeExprNode(AExprNode).Range;
if rng.Col1 >= colIndex then inc(rng.Col1);
if rng.Col2 >= colIndex then inc(rng.Col2);
TsCellRangeExprNode(AExprNode).Range := rng;
if TsCellRangeExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellRangeExprNode(AExprNode).GetSheet(1);
referencedSheet2 := TsCellRangeExprNode(AExprNode).GetSheet(2);
if TsCellRangeExprNode(AExprNode).Has3dLink and
(referencedSheet <> changedSheet) and
(referencedSheet2 <> changedSheet)
then
exit;
rng := TsCellRangeExprNode(AExprNode).Range;
if rng.Col1 >= colIndex then begin
inc(rng.Col1);
MustRebuildFormulas := true;
end;
if rng.Col2 >= colIndex then begin
inc(rng.Col2);
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
end;
procedure FixInsertedRow(AExprNode: TsExprNode; AData: Pointer;
procedure FixInsertedRow(AExprNode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
rowIndex: Cardinal;
changedSheet: TsBasicWorksheet;
referencedSheet, referencedSheet2: TsBasicWorksheet;
rng: TsCellRange;
begin
rowIndex := PtrInt(AData);
rowIndex := PtrInt(AData1);
changedSheet := TsBasicWorksheet(AData2);
if AExprNode is TsCellExprNode then
begin
if not TsCellexprNode(AExprNode).Has3dLink then
if TsCellExprNode(AExprNode).Row >= rowIndex then begin
TsCellExprNode(AExprNode).Row := TsCellExprNode(AExprNode).Row + 1;
MustRebuildFormulas := true;
end;
if TsCellExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellExprNode(AExprNode).GetSheet;
if TsCellExprNode(AExprNode).Has3dLink and (referencedSheet <> changedSheet) then
exit;
if TsCellExprNode(AExprNode).Row >= rowIndex then begin
TsCellExprNode(AExprNode).Row := TsCellExprNode(AExprNode).Row + 1;
MustRebuildFormulas := true;
end;
end else
if AExprNode is TsCellRangeExprNode then
begin
if not TsCellRangeExprNode(AExprNode).Has3dLink then begin
rng := TsCellRangeExprNode(AExprNode).Range;
if rng.Row1 >= rowIndex then inc(rng.Row1);
if rng.Row2 >= rowIndex then inc(rng.Row2);
TsCellRangeExprNode(AExprNode).Range := rng;
if TsCellRangeExprNode(AExprNode).Error <> errOK then
exit;
referencedSheet := TsCellRangeExprNode(AExprNode).GetSheet(1);
referencedSheet2 := TsCellRangeExprNode(AExprNode).GetSheet(2);
if TsCellRangeExprNode(AExprNode).Has3dLink and
(referencedSheet <> changedSheet) and
(referencedSheet2 <> changedSheet)
then
exit;
rng := TsCellRangeExprNode(AExprNode).Range;
if rng.Row1 >= rowIndex then begin
inc(rng.Row1);
MustRebuildFormulas := true;
end;
if rng.Row2 >= rowIndex then begin
inc(rng.Row2);
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
end;
@ -1436,7 +1505,9 @@ begin
Delete(ARow, ACol); // will release memory automatically
end;
procedure TsFormulas.DeleteRowOrCol(AIndex: Cardinal; IsRow: Boolean);
(*
procedure TsFormulas.DeleteRowOrCol(AIndex: Cardinal; IsRow: Boolean;
InSheet: TsBasicWorksheet);
var
node, nextnode: TAvgLvlTreeNode;
formula: PsFormula;
@ -1476,7 +1547,7 @@ begin
formula^.Text := formula^.Parser.Expression;
node := nextnode;
end;
end;
end; *)
procedure TsFormulas.DisposeData(var AData: Pointer);
begin
@ -1501,12 +1572,38 @@ begin
Result := PsFormula(FindByRowCol(ARow, ACol));
end;
{ In worksheet "InSheet" a row or column has been inserted or deleted at the
given index. "IsRow" tells whether it is a row or a column, and "IsDeleteing"
tells whether it has been deleted (true) or inserted (false).
This method must scan the formulas of the current worksheet whether there is
a reference to the modified sheet and must adapt the reference correspondingly
}
procedure TsFormulas.FixReferences(AIndex: Cardinal; IsRow, IsDeleting: Boolean;
InSheet: TsBasicWorksheet);
var
formula: PsFormula;
proc: TsExprNodeProc;
begin
if IsRow and IsDeleting then
proc := @FixDeletedRow
else if IsRow and not IsDeleting then
proc := @FixInsertedRow
else if not IsRow and IsDeleting then
proc := @FixDeletedCol
else
proc := @fixInsertedCol;
for formula in self do
if formula^.Parser.IterateNodes(proc, Pointer(PtrInt(AIndex)), InSheet) then
formula^.Text := formula^.Parser.Expression;
end;
// Formula enumerators (use in "for ... in" syntax)
function TsFormulas.GetEnumerator: TsFormulaEnumerator;
begin
Result := TsFormulaEnumerator.Create(self, 0, 0, $7FFFFFFF, $7FFFFFFF, false);
end;
(*
procedure TsFormulas.InsertRowOrCol(AIndex: Cardinal; IsRow: Boolean);
var
node: TAvgLvlTreeNode;
@ -1529,7 +1626,7 @@ begin
formula^.Text := formula^.Parser.Expression;
node := FindSuccessor(node);
end;
end;
end; *)
function TsFormulas.NewData: Pointer;
var

View File

@ -109,7 +109,7 @@ type
{ Proceudre executed when iterating through all nodes (Parser.IterateNodes).
The procedure sets the parameter MustRebuildFormula to true if the
text formula has to be rebuilt. }
TsExprNodeProc = procedure(ANode: TsExprNode; AData: Pointer;
TsExprNodeProc = procedure(ANode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
{ TsExprNode }
@ -124,7 +124,7 @@ type
function AsString: string; virtual; abstract;
procedure Check; virtual; //abstract;
function Has3DLink: Boolean; virtual;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
procedure IterateNodes(AProc: TsExprNodeProc; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean); virtual;
function NodeType: TsResultType; virtual; abstract;
function NodeValue: TsExpressionResult;
@ -144,7 +144,7 @@ type
constructor Create(AParser: TsExpressionParser; ALeft, ARight: TsExprNode);
destructor Destroy; override;
function Has3DLink: Boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
procedure IterateNodes(AProc: TsExprNodeProc; AData1, AData2: Pointer;
var MustRebuildFormulas: boolean); override;
property Left: TsExprNode read FLeft;
property Right: TsExprNode read FRight;
@ -567,7 +567,7 @@ type
function AsString: String; override;
procedure Check; override;
function Has3DLink: Boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
procedure IterateNodes(AProc: TsExprNodeProc; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean); override;
property ArgumentNodes: TsExprArgumentArray read FArgumentNodes;
property ArgumentParams: TsExprParameterArray read FArgumentParams;
@ -612,7 +612,6 @@ type
protected
function GetCol: Cardinal;
function GetRow: Cardinal;
function GetSheet: TsBasicWorksheet;
procedure GetNodeValue(out AResult: TsExpressionResult); override;
public
constructor Create(AParser: TsExpressionParser; AWorksheet: TsBasicWorksheet;
@ -620,11 +619,12 @@ type
function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: string; override;
procedure Check; override;
function GetSheet: TsBasicWorksheet;
function GetSheetIndex: Integer;
function GetSheetName: String;
function GetWorkbook: TsBasicWorkbook;
function Has3DLink: Boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
procedure IterateNodes(AProc: TsExprNodeProc; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean); override;
function NodeType: TsResultType; override;
procedure SetSheetIndex(AIndex: Integer);
@ -658,10 +658,11 @@ type
function AsRPNItem(ANext: PRPNItem): PRPNItem; override;
function AsString: String; override;
procedure Check; override;
function GetSheet(AIndex: TsCellRangeIndex): TsBasicWorksheet;
function GetSheetIndex(AIndex: TsCellRangeIndex): Integer;
function GetWorkbook: TsBasicWorkbook;
function Has3DLink: Boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
procedure IterateNodes(AProc: TsExprNodeProc; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean); override;
function NodeType: TsResultType; override;
procedure SetSheetIndex(AIndex: TsCellRangeIndex; AValue: Integer);
@ -788,7 +789,7 @@ type
function Evaluate: TsExpressionResult;
procedure EvaluateExpression(out AResult: TsExpressionResult);
function Has3DLinks: Boolean;
function IterateNodes(AProc: TsExprNodeProc; AData: Pointer): boolean;
function IterateNodes(AProc: TsExprNodeProc; AData1, AData2: Pointer): boolean;
procedure PrepareCopyMode(ASourceCell, ADestCell: PCell);
function ResultType: TsResultType;
@ -1988,10 +1989,10 @@ begin
end;
function TsExpressionParser.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer): Boolean;
AData1, AData2: Pointer): Boolean;
begin
Result := false;
FExprNode.IterateNodes(AProc, AData, Result);
FExprNode.IterateNodes(AProc, AData1, AData2, Result);
end;
procedure TsExpressionParser.SetDialect(const AValue: TsFormulaDialect);
@ -2776,10 +2777,11 @@ begin
Result := false;
end;
procedure TsExprNode.IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
procedure TsExprNode.IterateNodes(AProc: TsExprNodeProc; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
begin
Unused(AProc, AData, MustRebuildFormulas);
Unused(AProc, AData1, AData2);
Unused(MustRebuildFormulas);
// to be overridden by descendant classes
end;
@ -2834,12 +2836,12 @@ begin
end;
procedure TsBinaryOperationExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
AData1, AData2: Pointer; var MustRebuildFormulas: Boolean);
var
rebuildLeft, rebuildRight: Boolean;
begin
FLeft.IterateNodes(AProc, AData, rebuildLeft);
FRight.IterateNodes(AProc, AData, rebuildRight);
FLeft.IterateNodes(AProc, AData1, AData2, rebuildLeft);
FRight.IterateNodes(AProc, AData1, AData2, rebuildRight);
MustRebuildFormulas := MustRebuildFormulas or rebuildLeft or rebuildRight;
end;
@ -3795,12 +3797,12 @@ begin
end;
procedure TsFunctionExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
AData1, AData2: Pointer; var MustRebuildFormulas: Boolean);
var
i: Integer;
begin
for i:=0 to High(FArgumentParams) do
FArgumentNodes[i].IterateNodes(AProc, AData, MustRebuildFormulas);
FArgumentNodes[i].IterateNodes(AProc, AData1, AData2, MustRebuildFormulas);
end;
@ -3948,11 +3950,6 @@ begin
if FError <> errOK then begin
AResult.ResultType := rtError;
AResult.ResError := FError;
{
AResult.ResRow := GetRow;
AResult.ResCol := GetCol;
AResult.Worksheet := GetSheet;
}
exit;
end;
@ -4013,31 +4010,31 @@ end;
function TsCellExprNode.GetSheet: TsBasicWorksheet;
begin
if FSheetIndex = -1 then
Result := FWorksheet
else begin
if FHas3dLink then begin
Result := (GetWorkbook as TsWorkbook).GetWorksheetByIndex(FSheetIndex);
if Result = nil then FError := errIllegalREF;
end;
end else
Result := FWorksheet;
end;
function TsCellExprNode.GetSheetIndex: Integer;
var
book: TsWorkbook;
begin
book := GetWorkbook as TsWorkbook;
if FSheetIndex = -1 then
if FHas3dLink then
Result := FSheetIndex
else begin
book := GetWorkbook as TsWorkbook;
Result := book.GetWorksheetIndex(FWorksheet)
else
Result := FSheetIndex;
end;
end;
function TsCellExprNode.GetSheetName: String;
begin
if FSheetIndex = -1 then
Result := FWorksheet.Name
if FHas3dLink then
Result := TsWorkbook(GetWorkbook).GetWorksheetByIndex(FSheetIndex).Name
else
Result := TsWorkbook(GetWorkbook).GetWorksheetByIndex(FSheetIndex).Name;
Result := FWorksheet.Name;
end;
function TsCellExprNode.GetWorkbook: TsBasicWorkbook;
@ -4056,9 +4053,9 @@ begin
end;
procedure TsCellExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
AData1, AData2: Pointer; var MustRebuildFormulas: Boolean);
begin
AProc(self, AData, MustRebuildFormulas);
AProc(self, AData1, AData2, MustRebuildFormulas);
end;
procedure TsCellExprNode.SetSheetIndex(AIndex: Integer);
@ -4301,6 +4298,14 @@ begin
Result := (FWorksheet as TsWorksheet).Workbook;
end;
function TsCellRangeExprNode.GetSheet(AIndex: TsCellRangeIndex): TsBasicWorksheet;
begin
if FError <> errOK then
Result := nil
else
Result := TsWorkbook(GetWorkbook).GetWorksheetByIndex(GetSheetIndex(AIndex));
end;
function TsCellRangeExprNode.GetSheetIndex(AIndex: TsCellRangeIndex): Integer;
begin
Result := FSheetIndex[AIndex];
@ -4312,9 +4317,9 @@ begin
end;
procedure TsCellRangeExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
AData1, AData2: Pointer; var MustRebuildFormulas: Boolean);
begin
AProc(self, AData, MustRebuildFormulas);
AProc(self, AData1, AData2, MustRebuildFormulas);
end;
function TsCellRangeExprNode.NodeType: TsResultType;

View File

@ -7386,6 +7386,7 @@ var
i: Integer;
r: Cardinal;
formula: PsFormula;
sheet: TsWorksheet;
begin
// Fix merged cells
FMergedCells.DeleteRowOrCol(AIndex, IsRow);
@ -7396,8 +7397,14 @@ begin
// Fix hyperlinks
FHyperlinks.DeleteRowOrCol(AIndex, IsRow);
// Fix formulas
// Fix formulas:
// 1) Fix Row/Col index of in-sheet formulas
FFormulas.DeleteRowOrCol(AIndex, IsRow);
// 2) Fix formula references to this sheet
for i := 0 to FWorkbook.GetWorksheetcount-1 do begin
sheet := FWorkbook.GetWorksheetByIndex(i);
sheet.Formulas.FixReferences(AIndex, IsRow, true, self);
end;
// Delete cells
FCells.DeleteRowOrCol(AIndex, IsRow);
@ -7483,6 +7490,7 @@ var
col: PCol;
i: Integer;
rng: PsCellRange;
sheet: TsWorksheet;
begin
// Update row indexes of cell comments
FComments.InsertRowOrCol(AIndex, IsRow);
@ -7490,8 +7498,14 @@ begin
// Update row indexes of cell hyperlinks
FHyperlinks.InsertRowOrCol(AIndex, IsRow);
// Update row indexes of cell formulas
// Fix formulas:
// 1) Update Row/Col index of in-sheet formulas
FFormulas.InsertRowOrCol(AIndex, IsRow);
// 2) Fix formula references to this sheet
for i := 0 to FWorkbook.GetWorksheetcount-1 do begin
sheet := FWorkbook.GetWorksheetByIndex(i);
sheet.Formulas.FixReferences(AIndex, IsRow, false, self);
end;
// Update cell indexes of cell records
FCells.InsertRowOrCol(AIndex, IsRow);
@ -9600,7 +9614,7 @@ end;
{ AData points to the deleted worksheet }
procedure FixWorksheetDeletedCallback(ANode: TsExprNode; AData: Pointer;
procedure FixWorksheetDeletedCallback(ANode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
deletedindex: Integer;
@ -9609,10 +9623,12 @@ var
rngNode: TsCellRangeExprNode;
index, index1, index2: Integer;
begin
Unused(AData2);
if ANode is TsCellExprNode then
begin
cellNode := TsCellExprNode(ANode);
deletedSheet := TsWorksheet(AData);
deletedSheet := TsWorksheet(AData1);
deletedindex := TsWorkbook(cellNode.GetWorkbook).GetWorksheetIndex(deletedSheet);
index := cellNode.GetSheetIndex;
if deletedindex < index then begin
@ -9627,7 +9643,7 @@ begin
if ANode is TsCellRangeExprNode then
begin
rngNode := TsCellRangeExprNode(ANode);
deletedSheet := TsWorksheet(AData);
deletedSheet := TsWorksheet(AData1);
deletedIndex := TsWorkbook(rngNode.GetWorkbook).GetWorksheetIndex(deletedSheet);
index1 := rngNode.GetSheetIndex(1);
index2 := rngNode.GetSheetIndex(2);
@ -9663,7 +9679,7 @@ begin
fcWorksheetRenamed:
Result := true; // Nothing to do, no sheet names in formula nodes
fcWorksheetDeleted:
Result := AFormula^.Parser.IterateNodes(FixWorksheetDeletedCallback, AData);
Result := AFormula^.Parser.IterateNodes(FixWorksheetDeletedCallback, AData, nil);
end;
end;

View File

@ -2559,14 +2559,15 @@ begin
AStream.WriteWord(0);
end;
procedure DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData: Pointer;
procedure DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
sheetlist: TsBIFF8ExternSheetList;
sheetIdx, sheetIdx1, sheetIdx2: Integer;
begin
Unused(MustRebuildFormulas);
sheetlist := TsBIFF8ExternSheetList(AData);
Unused(AData2, MustRebuildFormulas);
sheetlist := TsBIFF8ExternSheetList(AData1);
if (ANode is TsCellExprNode) and TsCellExprNode(ANode).Has3DLink then
begin
sheetIdx := TsCellExprNode(ANode).GetSheetIndex;
@ -2593,7 +2594,7 @@ procedure TsSpreadBIFF8Writer.CollectExternData;
formula: PsFormula;
begin
for formula in ASheet.Formulas do
formula^.Parser.IterateNodes(@DoCollectSheetsWith3dRefs, FBiff8ExternSheets);
formula^.Parser.IterateNodes(@DoCollectSheetsWith3dRefs, FBiff8ExternSheets, nil);
end;
var

View File

@ -3463,7 +3463,7 @@ begin
end;
end;
procedure DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData: Pointer;
procedure DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData1, AData2: Pointer;
var MustRebuildFormulas: Boolean);
var
sheetlist: TsBIFFExternSheetList;
@ -3471,8 +3471,9 @@ var
workbook: TsWorkbook;
sheetName: String;
begin
Unused(MustRebuildFormulas);
sheetlist := TsBIFFExternSheetList(AData);
Unused(MustRebuildFormulas, AData2);
sheetlist := TsBIFFExternSheetList(AData1);
if (ANode is TsCellExprNode) and TsCellExprNode(ANode).Has3DLink then
begin
if (ANode as TsCellExprNode).Error <> errOK then
@ -3505,7 +3506,7 @@ function TsSpreadBIFFWriter.CollectExternData(AWorksheet: TsBasicWorksheet = nil
formula: PsFormula;
begin
for formula in ASheet.Formulas do
formula^.Parser.IterateNodes(@DoCollectSheetsWith3dRefs, ASheetList);
formula^.Parser.IterateNodes(@DoCollectSheetsWith3dRefs, ASheetList, nil);
end;
var