fpspreadsheet: Read and write xlsx files with formulas containing internal references to a range of cells within the same sheet (e.g., 'SUM(Sheet2!A1:B5)' ).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6403 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-05-10 17:58:05 +00:00
parent 3e132a9b12
commit 4f4c913ac0
2 changed files with 59 additions and 0 deletions

View File

@ -1689,6 +1689,12 @@ begin
if sheet = nil then
sheet := FWorksheet.Workbook.AddWorksheet(sheetName, true);
Result := TsCellExprNode.Create(self, sheet, CurrentToken, true)
end else
if TokenType = ttCellRange then begin
sheet := FWorksheet.WorkBook.GetWorksheetByName(sheetName);
if sheet = nil then
sheet := FWorksheet.Workbook.AddWorksheet(sheetName, true);
Result := TsCellRangeExprNode.Create(self, sheet, CurrentToken);
end;
end
else if (TokenType = ttCellRange) then

View File

@ -852,6 +852,9 @@ type
function GetNumberFormat(AIndex: Integer): TsNumFormatParams;
function GetNumberFormatCount: Integer;
{ Calculation }
procedure CalcFormulas;
{ Clipboard }
procedure CopyToClipboardStream(AStream: TStream; AFormat: TsSpreadsheetFormat;
AParams: TsStreamParams = []);
@ -1354,10 +1357,15 @@ end;
"not calculated" they are calculated and then tagged as "calculated".
This results in an iterative calculation procedure. In the end, all cells
are calculated.
NOTE: IF THE WORKSHEET CONTAINS CELLS WHICH LINK TO OTHER WORKSHEETS THEN
THIS CALCULATION MAY NOT BE CORRECT. USE THE SAME METHOD OF THE WORKBOOK
INSTEAD !!!
-------------------------------------------------------------------------------}
procedure TsWorksheet.CalcFormulas;
var
cell: PCell;
i: Integer;
begin
if (boIgnoreFormulas in Workbook.Options) then
exit;
@ -9657,6 +9665,51 @@ begin
Result := FNumFormatList.Count;
end;
{@@ ----------------------------------------------------------------------------
Calculates all formulas of the workbook.
Since formulas may reference not-yet-calculated cells, this occurs in
two steps:
1. All formula cells are marked as "not calculated".
2. Cells are calculated. If referenced cells are found as being
"not calculated" they are calculated and then tagged as "calculated".
This results in an iterative calculation procedure. In the end, all cells
are calculated.
-------------------------------------------------------------------------------}
procedure TsWorkbook.CalcFormulas;
var
cell: PCell;
p: Pointer;
sheet: TsWorksheet;
i: Integer;
begin
if (boIgnoreFormulas in Options) then
exit;
// prevent infinite loop due to triggering of formula calculation whenever
// a cell changes during execution of CalcFormulas.
inc(FCalculationLock);
try
// Step 1 - mark all formula cells as "not calculated"
for p in FWorksheets do begin
sheet := TsWorksheet(p);
for cell in sheet.Cells do
if HasFormula(cell) then
sheet.SetCalcState(cell, csNotCalculated);
end;
// Step 2 - calculate cells. If a not-yet-calculated cell is found it is
for p in FWorksheets do begin
sheet := TsWorksheet(p);
for cell in TsWorksheet(sheet).Cells do
if HasFormula(cell) and (cell^.ContentType <> cctError) then
sheet.CalcFormula(cell);
end;
finally
dec(FCalculationLock);
end;
end;
{@@ ----------------------------------------------------------------------------
Writes the selected cells to a stream for usage in the clipboard.
Transfer to the clipboard has do be done by the calling routine since