fpspreadsheet: Update cell flag cf3dFormula after parsing of a formula.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6424 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-05-16 22:31:30 +00:00
parent 79d7b2dc54
commit fd2a79771a
6 changed files with 50 additions and 16 deletions

View File

@ -617,7 +617,6 @@ type
TsCellRangeExprNode = class(TsExprNode)
private
FWorksheet: TsWorksheet;
// FWorksheet2: TsWorksheet;
FRow: array[TsCellRangeIndex] of Cardinal;
FCol: array[TsCellRangeIndex] of Cardinal;
FSheetIndex: array[TsCellRangeIndex] of Integer;
@ -719,6 +718,7 @@ type
protected
FFormatSettings: TFormatSettings;
FContains3DRef: Boolean;
class function BuiltinExpressionManager: TsBuiltInExpressionManager;
function BuildStringFormula(AFormatSettings: TFormatSettings): String;
procedure ParserError(Msg: String);
@ -771,9 +771,10 @@ type
property RPNFormula: TsRPNFormula read GetRPNFormula write SetRPNFormula;
property Identifiers: TsExprIdentifierDefs read FIdentifiers write SetIdentifiers;
property BuiltIns: TsBuiltInExprCategories read FBuiltIns write SetBuiltIns;
// property ActiveCell: PCell read FActiveCell write FActiveCell;
property Worksheet: TsWorksheet read FWorksheet;
property Dialect: TsFormulaDialect read FDialect write SetDialect;
property Contains3DRef: boolean read FContains3DRef;
end;
TsSpreadsheetParser = class(TsExpressionParser)
@ -3772,6 +3773,7 @@ begin
FCol := ACol;
FFlags := AFlags;
FCell := GetSheet.FindCell(FRow, FCol);
if Has3DLink then FParser.FContains3DRef := true;
end;
function TsCellExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem;
@ -3937,7 +3939,7 @@ begin
if ARange.Row2 = Cardinal(-1) then
ARange.Row2 := ARange.Row1;
if ARange.Row1 <= Arange.Row2 then
if ARange.Row1 <= ARange.Row2 then
begin
FRow[1] := ARange.Row1;
FRow[2] := ARange.Row2;
@ -3967,6 +3969,8 @@ begin
if (rfRelCol in AFlags) then Include(FFlags, rfRelCol2);
if (rfRelCol2 in AFlags) then Include(FFlags, rfRelCol);
end;
if Has3DLink then FParser.FContains3DRef := true;
end;
function TsCellRangeExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem;

View File

@ -1286,6 +1286,7 @@ var
link, txt: String;
cell: PCell;
formula: String;
has3DLink: Boolean;
begin
if (boIgnoreFormulas in Workbook.Options) then
exit;
@ -1297,6 +1298,7 @@ begin
try
try
parser.Expression := ACell^.FormulaValue;
has3DLink := parser.Contains3DRef;
res := parser.Evaluate;
except
on E:ECalcEngine do
@ -1342,6 +1344,8 @@ begin
WriteBlank(ACell);
end;
end;
if has3DLink then Include(ACell^.Flags, cf3DFormula)
else Exclude(ACell^.Flags, cf3DFormula);
finally
parser.Free;
end;
@ -5746,8 +5750,13 @@ begin
if (AFormula <> '') and (AFormula[1] = '=') then
AFormula := Copy(AFormula, 2, Length(AFormula));
parser := TsSpreadsheetParser.Create(self);
try
if ALocalized then begin
// Convert "localized" formula to standard format
parser := TsSpreadsheetParser.Create(self);
try
parser.LocalizedExpression[Workbook.FormatSettings] := AFormula;
parser.Expression := AFormula;
{
if ALocalized then
// Convert "localized" formula to standard format
parser.LocalizedExpression[Workbook.FormatSettings] := AFormula
@ -5757,8 +5766,10 @@ begin
if parser.Has3DLinks
then ACell.Flags := ACell.Flags + [cf3dFormula]
else ACell.Flags := ACell.Flags - [cf3dFormula];
finally
parser.Free;
}
finally
parser.Free;
end;
end;
end;

View File

@ -2554,7 +2554,7 @@ procedure TsSpreadBIFF8Writer.CollectExternData;
begin
if not HasFormula(cell) then
Continue;
if not (cf3dFormula in cell^.Flags) then
if (cell^.Flags * [cf3dFormula, cfCalculated] = [cfCalculated]) then
Continue;
parser := TsSpreadsheetParser.Create(ASheet);

View File

@ -3416,13 +3416,13 @@ function TsSpreadBIFFWriter.CollectExternData(AWorksheet: TsWorksheet = nil): In
begin
if not HasFormula(cell) then
Continue;
if not (cf3dFormula in cell^.Flags) then
if (cell^.Flags * [cf3dFormula, cfCalculated] = [cfCalculated]) then
Continue;
if (pos('[', ASheet.Name) = 0) then
kind := ebkInternal
else
kind := ebkExternal;
kind := ebkExternal; // External refs: [filename]Sheet1!A1
parser := TsSpreadsheetParser.Create(ASheet);
try

View File

@ -735,7 +735,7 @@ begin
try
workbook.Options := workbook.Options + [boReadFormulas];
workbook.ReadFromFile(TempFile, AFormat);
workbook.CalcFormulas;
// workbook.CalcFormulas;
if AFormat = sfExcel2 then
Fail('This test should not be executed')
@ -770,7 +770,7 @@ begin
if expected.ResultType = rtInteger then expected := FloatResult(expected.ResInteger);
{
// The now function result is volatile, i.e. changes continuously. The
// The NOW() function result is volatile, i.e. changes continuously. The
// time for the soll value was created such that we can expect to have
// the file value in the same second. Therefore we neglect the milliseconds.
if formula = '=NOW()' then begin

View File

@ -55,9 +55,11 @@ type
procedure SumMultiSheetRange_OOXML;
procedure SumMultiSheetRange_ODS;
procedure SumMultiSheetRange_FlippedCells_BIFF8;
procedure SumMultiSheetRange_FlippedCells_OOXML;
procedure SumMultiSheetRange_FlippedSheets_OOXML;
procedure SumMultiSheetRange_FlippedSheetsAndCells_OOXML;
procedure SumMultiSheetRange_FlippedSheetsAndCells_ODS;
end;
@ -139,7 +141,7 @@ begin
// Read formula before saving
actualFormula := cell^.Formulavalue;
CheckEquals(AExpectedFormula, actualFormula, 'Unsaved formula text mismatch');
CheckEquals(AFormula, actualFormula, 'Unsaved formula text mismatch');
// Read calculated value before saving
actualvalue := worksheet.ReadAsNumber(TESTCELL_ROW, TESTCELL_COL);
@ -164,6 +166,7 @@ begin
cell := worksheet.FindCell(TESTCELL_ROW, TESTCELL_COL);
actualformula := cell^.FormulaValue;
// When writing ranges are reconstructed in correct order.
CheckEquals(AExpectedFormula, actualformula, 'Saved formula text mismatch.');
finally
workbook.Free;
@ -301,19 +304,35 @@ end;
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedSheetsAndCells_OOXML;
begin
TestFloatFormula('SUM(Sheet3:Sheet2!C5:C3)', 55.0, ftkCellRangeSheetRange, sfOOXML, 'SUM(Sheet2:Sheet3!C3:C5)');
// In OOXML the range is written literally.
TestFloatFormula('SUM(Sheet3:Sheet2!C5:C3)', 55.0, ftkCellRangeSheetRange, sfOOXML);
end;
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedSheetsAndCells_ODS;
begin
// ODS requires conversion of the formula which results in reordering of ranges.
TestFloatFormula('SUM(Sheet3:Sheet2!C5:C3)', 55.0, ftkCellRangeSheetRange, sfOpenDocument, 'SUM(Sheet2:Sheet3!C3:C5)');
end;
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedCells_BIFF8;
begin
// Upon writing the ranges are reconstructed for BIFF in correct order.
TestFloatFormula('SUM(Sheet2:Sheet3!C5:C3)', 55.0, ftkCellRangeSheetRange, sfExcel8, 'SUM(Sheet2:Sheet3!C3:C5)');
end;
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedCells_OOXML;
begin
TestFloatFormula('SUM(Sheet2:Sheet3!C5:C3)', 55.0, ftkCellRangeSheetRange, sfOOXML, 'SUM(Sheet2:Sheet3!C3:C5)');
// In OOXML the range is written literally.
TestFloatFormula('SUM(Sheet2:Sheet3!C5:C3)', 55.0, ftkCellRangeSheetRange, sfOOXML);
end;
procedure TSpreadSingleFormulaTests.SumMultiSheetRange_FlippedSheets_OOXML;
begin
TestFloatFormula('SUM(Sheet3:Sheet2!C3:C5)', 55.0, ftkCellRangeSheetRange, sfOOXML, 'SUM(Sheet2:Sheet3!C3:C5)');
// In OOXML the range is written literally.
TestFloatFormula('SUM(Sheet3:Sheet2!C3:C5)', 55.0, ftkCellRangeSheetRange, sfOOXML);
end;
initialization
// Register to include these tests in a full run
RegisterTest(TSpreadSingleFormulaTests);