fpspreadsheet: make sure that formulas are only recalculated when needed (in particalar only once after loading a file). Rename worksheet option soCalcAfterSaving to boCalcAfterSaving and assign it to the Workbook. (Add section "Incompatible changes" to wiki).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3478 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-08-13 19:23:59 +00:00
parent 2dd6598e20
commit 67186349be
4 changed files with 48 additions and 32 deletions

View File

@@ -134,8 +134,9 @@ begin
workbook := TsWorkbook.Create; workbook := TsWorkbook.Create;
try try
workbook.Options := workbook.Options + [boCalcBeforeSaving];
worksheet := workbook.AddWorksheet('Financial'); worksheet := workbook.AddWorksheet('Financial');
worksheet.Options := worksheet.Options + [soCalcBeforeSaving];
worksheet.WriteColWidth(0, 40); worksheet.WriteColWidth(0, 40);
worksheet.WriteColWidth(1, 15); worksheet.WriteColWidth(1, 15);

View File

@@ -22,12 +22,14 @@ var
worksheet: TsWorksheet; worksheet: TsWorksheet;
const const
OutputFile='test_calc.xls'; OutputFile='test_calc.xls';
begin begin
writeln('Starting program.'); writeln('Starting program.');
workbook := TsWorkbook.Create; workbook := TsWorkbook.Create;
try try
workbook.Options := workbook.Options + [boCalcBeforeSaving];
worksheet := workbook.AddWorksheet('Calc_test'); worksheet := workbook.AddWorksheet('Calc_test');
worksheet.Options := worksheet.Options + [soCalcBeforeSaving];
worksheet.WriteColWidth(0, 20); worksheet.WriteColWidth(0, 20);
// A1 // A1

View File

@@ -459,12 +459,8 @@ type
@param soShowHeaders Show or hide the column or row headers of the spreadsheet @param soShowHeaders Show or hide the column or row headers of the spreadsheet
@param soHasFrozenPanes If set a number of rows and columns of the spreadsheet @param soHasFrozenPanes If set a number of rows and columns of the spreadsheet
is fixed and does not scroll. The number is defined by is fixed and does not scroll. The number is defined by
LeftPaneWidth and TopPaneHeight. LeftPaneWidth and TopPaneHeight. }
@param soCalcBeforeSaving Calculates formulas before saving the file. Otherwise TsSheetOption = (soShowGridLines, soShowHeaders, soHasFrozenPanes);
there are no results when the file is loaded back by
fpspreadsheet. }
TsSheetOption = (soShowGridLines, soShowHeaders, soHasFrozenPanes,
soCalcBeforeSaving);
{@@ Set of user interface options {@@ Set of user interface options
@ see TsSheetOption } @ see TsSheetOption }
@@ -750,19 +746,21 @@ type
{@@ {@@
Option flags for the workbook Option flags for the workbook
@param boVirtualMode If in virtual mode date are not taken from cells @param boVirtualMode If in virtual mode date are not taken from cells
when a spreadsheet is written to file, but are when a spreadsheet is written to file, but are
provided by means of the event OnWriteCellData. provided by means of the event OnWriteCellData.
Similarly, when data are read they are not added as Similarly, when data are read they are not added as
cells but passed the the event OnReadCellData; cells but passed the the event OnReadCellData;
@param boBufStream When this option is set a buffered stream is used @param boBufStream When this option is set a buffered stream is used
for writing (a memory stream swapping to disk) or for writing (a memory stream swapping to disk) or
reading (a file stream pre-reading chunks of data reading (a file stream pre-reading chunks of data
to memory) to memory)
@param boAutoCalc Automatically recalculate rpn formulas whenever @param boAutoCalc Automatically recalculate rpn formulas whenever
a cell value changes. a cell value changes.
} @param boCalcBeforeSaving Calculates formulas before saving the file.
TsWorkbookOption = (boVirtualMode, boBufStream, boAutoCalc); Otherwise there are no results when the file is
loaded back by fpspreadsheet. }
TsWorkbookOption = (boVirtualMode, boBufStream, boAutoCalc, boCalcBeforeSaving);
{@@ {@@
Set of options flags for the workbook } Set of options flags for the workbook }
@@ -800,7 +798,7 @@ type
FVirtualColCount: Cardinal; FVirtualColCount: Cardinal;
FVirtualRowCount: Cardinal; FVirtualRowCount: Cardinal;
FWriting: Boolean; FWriting: Boolean;
FCalculating: Boolean; FCalculationLock: Integer;
FOptions: TsWorkbookOptions; FOptions: TsWorkbookOptions;
FOnWriteCellData: TsWorkbookWriteCellDataEvent; FOnWriteCellData: TsWorkbookWriteCellDataEvent;
FOnReadCellData: TsWorkbookReadCellDataEvent; FOnReadCellData: TsWorkbookReadCellDataEvent;
@@ -816,6 +814,7 @@ type
procedure GetLastRowColIndex(out ALastRow, ALastCol: Cardinal); procedure GetLastRowColIndex(out ALastRow, ALastCol: Cardinal);
procedure PrepareBeforeReading; procedure PrepareBeforeReading;
procedure PrepareBeforeSaving; procedure PrepareBeforeSaving;
procedure ReCalc;
procedure RemoveWorksheetsCallback(data, arg: pointer); procedure RemoveWorksheetsCallback(data, arg: pointer);
procedure UpdateCaches; procedure UpdateCaches;
@@ -1730,7 +1729,7 @@ var
begin begin
// prevent infinite loop due to triggering of formula calculation whenever // prevent infinite loop due to triggering of formula calculation whenever
// a cell changes during execution of CalcFormulas. // a cell changes during execution of CalcFormulas.
FWorkbook.FCalculating := true; inc(FWorkbook.FCalculationLock);
try try
// Step 1 - mark all formula cells as "not calculated" // Step 1 - mark all formula cells as "not calculated"
node := FCells.FindLowest; node := FCells.FindLowest;
@@ -1747,7 +1746,7 @@ begin
node := FCells.FindSuccessor(node); node := FCells.FindSuccessor(node);
end; end;
finally finally
FWorkbook.FCalculating := false; dec(FWorkbook.FCalculationLock);
end; end;
end; end;
@@ -1914,7 +1913,7 @@ end;
} }
procedure TsWorksheet.ChangedCell(ARow, ACol: Cardinal); procedure TsWorksheet.ChangedCell(ARow, ACol: Cardinal);
begin begin
if not FWorkbook.FCalculating and (boAutoCalc in FWorkbook.Options) then if (FWorkbook.FCalculationLock = 0) and (boAutoCalc in FWorkbook.Options) then
begin begin
if CellUsedInFormula(ARow, ACol) then if CellUsedInFormula(ARow, ACol) then
CalcFormulas; CalcFormulas;
@@ -4849,11 +4848,22 @@ begin
UpdateCaches; UpdateCaches;
// Calculated formulas (if requested) // Calculated formulas (if requested)
for sheet in FWorksheets do if (boCalcBeforeSaving in FOptions) then
if (soCalcBeforeSaving in sheet.Options) then for sheet in FWorksheets do
sheet.CalcFormulas; sheet.CalcFormulas;
end; end;
{@@
Recalculates rpn formulas in all worksheets
}
procedure TsWorkbook.Recalc;
var
sheet: TsWorksheet;
begin
for sheet in FWorksheets do
sheet.CalcFormulas;
end;
{@@ {@@
Helper method for clearing the spreadsheet list. Helper method for clearing the spreadsheet list.
} }
@@ -5026,6 +5036,8 @@ begin
PrepareBeforeReading; PrepareBeforeReading;
AReader.ReadFromFile(AFileName, Self); AReader.ReadFromFile(AFileName, Self);
UpdateCaches; UpdateCaches;
if (boAutoCalc in Options) then
Recalc;
FFormat := AFormat; FFormat := AFormat;
finally finally
AReader.Free; AReader.Free;
@@ -5083,7 +5095,7 @@ var
SheetType: TsSpreadsheetFormat; SheetType: TsSpreadsheetFormat;
lException: Exception; lException: Exception;
begin begin
lException := pointer(1); lException := pointer(1); // Must not be nil initially
SheetType := sfExcel8; SheetType := sfExcel8;
while (SheetType in [sfExcel2..sfExcel8, sfOpenDocument, sfOOXML]) and (lException <> nil) do while (SheetType in [sfExcel2..sfExcel8, sfOpenDocument, sfOOXML]) and (lException <> nil) do
begin begin
@@ -5092,8 +5104,7 @@ begin
ReadFromFile(AFileName, SheetType); ReadFromFile(AFileName, SheetType);
lException := nil; lException := nil;
except except
on E: Exception do on E: Exception do { do nothing } ;
{ do nothing } ;
end; end;
if lException = nil then Break; if lException = nil then Break;
end; end;
@@ -5115,6 +5126,8 @@ begin
PrepareBeforeReading; PrepareBeforeReading;
AReader.ReadFromStream(AStream, Self); AReader.ReadFromStream(AStream, Self);
UpdateCaches; UpdateCaches;
if (boAutoCalc in Options) then
Recalc;
finally finally
AReader.Free; AReader.Free;
end; end;

View File

@@ -180,10 +180,10 @@ begin
// Create test workbook // Create test workbook
MyWorkbook := TsWorkbook.Create; MyWorkbook := TsWorkbook.Create;
try try
MyWorkSheet:= MyWorkBook.AddWorksheet(SHEET); MyWorkbook.Options := MyWorkbook.Options + [boCalcBeforeSaving];
MyWorkSheet.Options := MyWorkSheet.Options + [soCalcBeforeSaving];
// Calculation of rpn formulas must be activated explicitly! // Calculation of rpn formulas must be activated explicitly!
MyWorkSheet:= MyWorkBook.AddWorksheet(SHEET);
{ Write out test formulas. { Write out test formulas.
This include file creates various rpn formulas and stores the expected This include file creates various rpn formulas and stores the expected
results in array "sollValues". results in array "sollValues".