fpspreadsheet: Fix iterative 3d formula correction terminating prematurely.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6449 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-06-02 11:46:57 +00:00
parent 79f14f6143
commit f68c5da31c
5 changed files with 76 additions and 61 deletions

View File

@ -252,23 +252,23 @@ end;
{ Call-back function for formulas when rows/cols are inserted/deleted }
function FixDeletedCol(AExprNode: TsExprNode; AData: Pointer): Boolean;
procedure FixDeletedCol(AExprNode: TsExprNode; AData: Pointer;
var MustRebuildFormulas: Boolean);
var
colIndex: Cardinal;
rng: TsCellRange;
begin
Result := false;
colIndex := PtrInt(AData);
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;
Result := true;
MustRebuildFormulas := true;
end else
if TsCellExprNode(AExprNode).Col = colIndex then begin
TsCellExprNode(AExprNode).Error := errIllegalRef;
Result := true;
MustRebuildFormulas := true;
end;
end else
if AExprNode is TsCellRangeExprNode then
@ -277,15 +277,15 @@ begin
rng := TsCellRangeExprNode(AExprNode).Range;
if (rng.Col1 = colIndex) and (rng.Col2 = colIndex) then begin
TsCellRangeExprNode(AExprNode).Error := errIllegalRef;
Result := true;
MustRebuildFormulas := true;
end else begin
if rng.Col1 > colIndex then begin
dec(rng.Col1);
Result := true;
MustRebuildFormulas := true;
end;
if rng.Col2 >= colIndex then begin
dec(rng.Col2);
Result := true;
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
@ -293,23 +293,23 @@ begin
end;
end;
function FixDeletedRow(AExprNode: TsExprNode; AData: Pointer): Boolean;
procedure FixDeletedRow(AExprNode: TsExprNode; AData: Pointer;
var MustRebuildFormulas: Boolean);
var
rowIndex: Cardinal;
rng: TsCellRange;
begin
Result := false;
rowIndex := PtrInt(AData);
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;
Result := true;
MustRebuildFormulas := true;
end else
if TsCellExprNode(AExprNode).Row = rowIndex then begin
TsCelLExprNode(AExprNode).Error := errIllegalRef;
Result := true;
MustRebuildFormulas := true;
end;
end else
if AExprNode is TsCellRangeExprNode then
@ -318,16 +318,16 @@ begin
rng := TsCellRangeExprNode(AExprNode).Range;
if (rng.Row1 = rowIndex) and (rng.Row2 = rowIndex) then begin
TsCellRangeExprNode(AExprNode).Error := errIllegalRef;
Result := true;
MustRebuildFormulas := true;
end else
begin
if rng.Row1 > rowIndex then begin
dec(rng.Row1);
Result := true;
MustRebuildFormulas := true;
end;
if rng.Row2 >= rowIndex then begin
dec(rng.Row2);
Result := true;
MustRebuildFormulas := true;
end;
TsCellRangeExprNode(AExprNode).Range := rng;
end;
@ -335,19 +335,19 @@ begin
end;
end;
function FixInsertedCol(AExprNode: TsExprNode; AData: Pointer): Boolean;
procedure FixInsertedCol(AExprNode: TsExprNode; AData: Pointer;
var MustRebuildFormulas: Boolean);
var
colIndex: Cardinal;
rng: TsCellRange;
begin
Result := false;
colIndex := PtrInt(AData);
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;
Result := true;
MustRebuildFormulas := true;
end;
end else
if AExprNode is TsCellRangeExprNode then
@ -357,24 +357,24 @@ begin
if rng.Col1 >= colIndex then inc(rng.Col1);
if rng.Col2 >= colIndex then inc(rng.Col2);
TsCellRangeExprNode(AExprNode).Range := rng;
Result := true;
MustRebuildFormulas := true;
end;
end;
end;
function FixInsertedRow(AExprNode: TsExprNode; AData: Pointer): Boolean;
procedure FixInsertedRow(AExprNode: TsExprNode; AData: Pointer;
var MustRebuildFormulas: Boolean);
var
rowIndex: Cardinal;
rng: TsCellRange;
begin
Result := false;
rowIndex := PtrInt(AData);
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;
Result := true;
MustRebuildFormulas := true;
end;
end else
if AExprNode is TsCellRangeExprNode then
@ -384,7 +384,7 @@ begin
if rng.Row1 >= rowIndex then inc(rng.Row1);
if rng.Row2 >= rowIndex then inc(rng.Row2);
TsCellRangeExprNode(AExprNode).Range := rng;
Result := true;
MustRebuildFormulas := true;
end;
end;
end;

View File

@ -106,9 +106,11 @@ type
PsExpressionResult = ^TsExpressionResult;
TsExprParameterArray = array of TsExpressionResult;
{ Function executed when iterating through all nodes (Parser.IterateNodes).
The function returns true if the text formula has to be rebuilt. }
TsExprNodeFunc = function(ANode: TsExprNode; AData: Pointer): Boolean;
{ 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;
var MustRebuildFormulas: Boolean);
{ TsExprNode }
TsExprNode = class(TObject)
@ -122,7 +124,8 @@ type
function AsString: string; virtual; abstract;
procedure Check; virtual; //abstract;
function Has3DLink: Boolean; virtual;
function IterateNodes(AFunc: TsExprNodeFunc; AData: Pointer): Boolean; virtual;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
var MustRebuildFormulas: Boolean); virtual;
function NodeType: TsResultType; virtual; abstract;
function NodeValue: TsExpressionResult;
property Parser: TsExpressionParser read FParser;
@ -141,7 +144,8 @@ type
constructor Create(AParser: TsExpressionParser; ALeft, ARight: TsExprNode);
destructor Destroy; override;
function Has3DLink: Boolean; override;
function IterateNodes(AFunc: TsExprNodeFunc; AData: Pointer): boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
var MustRebuildFormulas: boolean); override;
property Left: TsExprNode read FLeft;
property Right: TsExprNode read FRight;
end;
@ -563,7 +567,8 @@ type
function AsString: String; override;
procedure Check; override;
function Has3DLink: Boolean; override;
function IterateNodes(AFunc: TsExprNodeFunc; AData: Pointer): Boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
var MustRebuildFormulas: Boolean); override;
property ArgumentNodes: TsExprArgumentArray read FArgumentNodes;
property ArgumentParams: TsExprParameterArray read FArgumentParams;
end;
@ -618,7 +623,8 @@ type
function GetSheetName: String;
function GetWorkbook: TsBasicWorkbook;
function Has3DLink: Boolean; override;
function IterateNodes(AFunc: TsExprNodeFunc; AData: Pointer): Boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
var MustRebuildFormulas: Boolean); override;
function NodeType: TsResultType; override;
procedure SetSheetIndex(AIndex: Integer);
property Col: Cardinal read FCol write FCol; // Be careful when modifying Col and Row
@ -654,7 +660,8 @@ type
function GetSheetIndex(AIndex: TsCellRangeIndex): Integer;
function GetWorkbook: TsBasicWorkbook;
function Has3DLink: Boolean; override;
function IterateNodes(AFunc: TsExprNodeFunc; AData: Pointer): Boolean; override;
procedure IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
var MustRebuildFormulas: Boolean); override;
function NodeType: TsResultType; override;
procedure SetSheetIndex(AIndex: TsCellRangeIndex; AValue: Integer);
property Error: TsErrorValue read FError write FError;
@ -780,7 +787,7 @@ type
function Evaluate: TsExpressionResult;
procedure EvaluateExpression(out AResult: TsExpressionResult);
function Has3DLinks: Boolean;
function IterateNodes(AFunc: TsExprNodeFunc; AData: Pointer): boolean;
function IterateNodes(AProc: TsExprNodeProc; AData: Pointer): boolean;
procedure PrepareCopyMode(ASourceCell, ADestCell: PCell);
function ResultType: TsResultType;
@ -1979,10 +1986,11 @@ begin
Result := FExprNode.Has3DLink;
end;
function TsExpressionParser.IterateNodes(AFunc: TsExprNodeFunc;
function TsExpressionParser.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer): Boolean;
begin
Result := FExprNode.IterateNodes(AFunc, AData);
Result := false;
FExprNode.IterateNodes(AProc, AData, Result);
end;
procedure TsExpressionParser.SetDialect(const AValue: TsFormulaDialect);
@ -2767,9 +2775,10 @@ begin
Result := false;
end;
function TsExprNode.IterateNodes(AFunc: TsExprNodeFunc; AData: Pointer): Boolean;
procedure TsExprNode.IterateNodes(AProc: TsExprNodeProc; AData: Pointer;
var MustRebuildFormulas: Boolean);
begin
Unused(AFunc, AData);
Unused(AProc, AData, MustRebuildFormulas);
// to be overridden by descendant classes
end;
@ -2823,10 +2832,14 @@ begin
Result := FLeft.Has3DLink or FRight.Has3DLink;
end;
function TsBinaryOperationExprNode.IterateNodes(AFunc: TsExprNodeFunc;
AData: Pointer): Boolean;
procedure TsBinaryOperationExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
var
rebuildLeft, rebuildRight: Boolean;
begin
Result := FLeft.IterateNodes(AFunc, AData) or FRight.IterateNodes(AFunc, AData);
FLeft.IterateNodes(AProc, AData, rebuildLeft);
FRight.IterateNodes(AProc, AData, rebuildRight);
MustRebuildFormulas := MustRebuildFormulas or rebuildLeft or rebuildRight;
end;
function TsBinaryOperationExprNode.HasError(out AResult: TsExpressionResult): Boolean;
@ -3780,14 +3793,13 @@ begin
Result := false;
end;
function TsFunctionExprNode.IterateNodes(AFunc: TsExprNodeFunc;
AData: Pointer): Boolean;
procedure TsFunctionExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
var
i: Integer;
begin
Result := false;
for i:=0 to High(FArgumentParams) do
Result := Result or FArgumentNodes[i].IterateNodes(AFunc, AData);
FArgumentNodes[i].IterateNodes(AProc, AData, MustRebuildFormulas);
end;
@ -4037,10 +4049,10 @@ begin
Result := rtCell;
end;
function TsCellExprNode.IterateNodes(AFunc: TsExprNodeFunc;
AData: Pointer): Boolean;
procedure TsCellExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
begin
Result := AFunc(self, AData);
AProc(self, AData, MustRebuildFormulas);
end;
procedure TsCellExprNode.SetSheetIndex(AIndex: Integer);
@ -4293,10 +4305,10 @@ begin
Result := F3dRange;
end;
function TsCellRangeExprNode.IterateNodes(AFunc: TsExprNodeFunc;
AData: Pointer): Boolean;
procedure TsCellRangeExprNode.IterateNodes(AProc: TsExprNodeProc;
AData: Pointer; var MustRebuildFormulas: Boolean);
begin
Result := AFunc(self, AData);
AProc(self, AData, MustRebuildFormulas);
end;
function TsCellRangeExprNode.NodeType: TsResultType;

View File

@ -1137,6 +1137,7 @@ end;
{@@ ----------------------------------------------------------------------------
Destructor of the TsWorksheet class.
Releases all memory, but does not delete from the workbook's worksheetList !!!
NOTE: Don't call directly. Always use Workbook.RemoveWorksheet to remove a
worksheet from a workbook.
-------------------------------------------------------------------------------}
@ -9599,7 +9600,8 @@ end;
{ AData points to the deleted worksheet }
function FixWorksheetDeletedCallback(ANode: TsExprNode; AData: Pointer): Boolean;
procedure FixWorksheetDeletedCallback(ANode: TsExprNode; AData: Pointer;
var MustRebuildFormulas: Boolean);
var
deletedindex: Integer;
deletedSheet: TsWorksheet;
@ -9607,7 +9609,6 @@ var
rngNode: TsCellRangeExprNode;
index, index1, index2: Integer;
begin
Result := false;
if ANode is TsCellExprNode then
begin
cellNode := TsCellExprNode(ANode);
@ -9616,11 +9617,11 @@ begin
index := cellNode.GetSheetIndex;
if deletedindex < index then begin
cellNode.SetSheetIndex(index-1);
Result := true;
MustRebuildFormulas := true;
end else
if deletedIndex = index then begin
cellNode.Error := errIllegalRef;
Result := true;
MustRebuildFormulas := true;
end;
end else
if ANode is TsCellRangeExprNode then
@ -9633,23 +9634,23 @@ begin
if deletedIndex < index1 then begin
rngNode.SetSheetIndex(1, index1-1);
rngNode.SetSheetIndex(2, index2-1);
Result := true;
MustRebuildFormulas := true;
end else
if (deletedIndex > index1) and (deletedIndex < index2) then begin
rngNode.SetSheetIndex(2, index2-1);
Result := true;
MustRebuildFormulas := true;
end else
if (deletedIndex = index1) and (index1 <> index2) then begin
rngNode.SetSheetIndex(2, index2-1);
Result := true;
MustRebuildFormulas := true;
end else
if (deletedIndex = index2) and (index1 <> index2) then begin
rngNode.SetSheetIndex(2, index2-1);
Result := true;
MustRebuildFormulas := true;
end else
if (deletedIndex = index1) and (deletedIndex = index2) then begin
rngNode.Error := errIllegalRef;
Result := true;
MustRebuildFormulas := true;
end;
end;
end;

View File

@ -2559,11 +2559,13 @@ begin
AStream.WriteWord(0);
end;
function DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData: Pointer): Boolean;
procedure DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData: Pointer;
var MustRebuildFormulas: Boolean);
var
sheetlist: TsBIFF8ExternSheetList;
sheetIdx, sheetIdx1, sheetIdx2: Integer;
begin
Unused(MustRebuildFormulas);
sheetlist := TsBIFF8ExternSheetList(AData);
if (ANode is TsCellExprNode) and TsCellExprNode(ANode).Has3DLink then
begin
@ -2577,7 +2579,6 @@ begin
for sheetIdx := sheetIdx1 to sheetIdx2 do
sheetList.AddSheets('', nil, sheetIdx1, sheetIdx2);
end;
Result := false;
end;
{@@ ----------------------------------------------------------------------------

View File

@ -3463,12 +3463,14 @@ begin
end;
end;
function DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData: Pointer): Boolean;
procedure DoCollectSheetsWith3dRefs(ANode: TsExprNode; AData: Pointer;
var MustRebuildFormulas: Boolean);
var
sheetlist: TsBIFFExternSheetList;
sheetIdx, sheetIdx1, sheetIdx2: Integer;
workbook: TsWorkbook;
begin
Unused(MustRebuildFormulas);
sheetlist := TsBIFFExternSheetList(AData);
if (ANode is TsCellExprNode) and TsCellExprNode(ANode).Has3DLink then
sheetList.AddSheet(TsCellExprNode(ANode).GetSheetName, ebkInternal)
@ -3481,7 +3483,6 @@ begin
for sheetIdx := sheetIdx1 to sheetIdx2 do
sheetList.AddSheet(workbook.GetWorksheetByIndex(sheetIdx).Name, ebkInternal);
end;
Result := false; // No need to rebuild the text formula
end;
{@@ ----------------------------------------------------------------------------