fpspreadsheet: Add WorkbookOption boAbortReadOnFormulaError. Off by default, i.e. Reader continues after finding an unknown formula.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6207 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2018-02-20 17:35:23 +00:00
parent 16664fcf64
commit e47e969aec
6 changed files with 95 additions and 51 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="10"/>
<Version Value="11"/>
<PathDelim Value="\"/>
<General>
<Flags>
@ -23,9 +23,16 @@
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
</local>
<FormatVersion Value="2"/>
<Modes Count="1">
<Mode0 Name="default">
<local>
<LaunchingApplication PathPlusParams="\usr\X11R6\bin\xterm -T 'Lazarus Run Output' -e $(LazarusDir)\tools\runwait.sh $(TargetCmdLine)"/>
</local>
</Mode0>
</Modes>
</RunParams>
<RequiredPackages Count="1">
<Item1>
@ -46,6 +53,7 @@
<Filename Value="opendocread"/>
</Target>
<SearchPaths>
<IncludeFiles Value="..\..\..\source"/>
<OtherUnitFiles Value="..\..\..\source\common"/>
<UnitOutputDirectory Value="..\..\lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>

View File

@ -2357,10 +2357,25 @@ begin
// ... convert to Excel "A1" dialect used by fps by defailt
parser := TsSpreadsheetParser.Create(FWorksheet);
try
parser.Dialect := fdOpenDocument;
parser.LocalizedExpression[FPointSeparatorSettings] := formula;
parser.Dialect := fdExcelA1;
formula := parser.Expression;
try
parser.Dialect := fdOpenDocument;
parser.LocalizedExpression[FPointSeparatorSettings] := formula;
parser.Dialect := fdExcelA1;
formula := parser.Expression;
except
on E:EExprParser do
begin
Workbook.AddErrorMsg(E.Message);
formula := '';
if (boAbortReadOnFormulaError in Workbook.Options) then raise;
end;
on E:ECalcEngine do
begin
Workbook.AddErrorMsg(E.Message);
formula := '';
if (boAbortReadOnFormulaError in Workbook.Options) then raise;
end;
end;
finally
parser.Free;
end;

View File

@ -654,8 +654,8 @@ type
@param boVirtualMode If in virtual mode date are not taken from cells
when a spreadsheet is written to file, but are
provided by means of the event OnWriteCellData.
Similarly, when data are read they are not added as
cells but passed the the event OnReadCellData;
Similarly, when data are read they are not added
as cells but passed the the event OnReadCellData;
@param boBufStream When this option is set a buffered stream is used
for writing (a memory stream swapping to disk) or
reading (a file stream pre-reading chunks of data
@ -663,19 +663,22 @@ type
@param boFileStream Uses file streams and temporary files during
reading and writing. Lowest memory consumptions,
but slow.
@param boAutoCalc Automatically recalculate rpn formulas whenever
a cell value changes.
@param boAutoCalc Automatically recalculate formulas whenever a
cell value changes.
@param boCalcBeforeSaving Calculates formulas before saving the file.
Otherwise there are no results when the file is
loaded back by fpspreadsheet.
@param boReadFormulas Allows to turn off reading of rpn formulas; this is
a precaution since formulas not correctly
@param boReadFormulas Allows to turn off reading of rpn formulas; this
is a precaution since formulas not correctly
implemented by fpspreadsheet could crash the
reading operation.
@param boWriteZoomfactor Instructs the writer to write the current zoom
factors of the worksheets to file. }
factors of the worksheets to file.
@param boAbortReadOnFormulaError Aborts reading if a formula error is
encountered }
TsWorkbookOption = (boVirtualMode, boBufStream, boFileStream,
boAutoCalc, boCalcBeforeSaving, boReadFormulas, boWriteZoomFactor);
boAutoCalc, boCalcBeforeSaving, boReadFormulas, boWriteZoomFactor,
boAbortReadOnFormulaError);
{@@ Set of option flags for the workbook }
TsWorkbookOptions = set of TsWorkbookOption;

View File

@ -1015,9 +1015,6 @@ begin
finally
OLEStorage.Free;
end;
// InternalReadFromStream(OLEStream); // wp: moved up
finally
OLEStream.Free;
end;

View File

@ -1662,6 +1662,7 @@ var
err: TsErrorValue;
ok: Boolean;
cell: PCell;
msg: String;
begin
{ Index to XF Record }
ReadRowColXF(AStream, ARow, ACol, XF);
@ -1720,7 +1721,17 @@ begin
begin
ok := ReadRPNTokenArray(AStream, cell);
if not ok then
FWorksheet.WriteErrorValue(cell, errFormulaNotSupported);
begin
msg := Format(rsFormulaNotSupported, [
GetCellString(ARow, ACol), '.xls'
]);
if (boAbortReadOnFormulaError in Workbook.Options) then
raise Exception.Create(msg)
else begin
FWorksheet.WriteErrorValue(cell, errFormulaNotSupported);
FWorkbook.AddErrorMsg(msg);
end;
end;
end;
{Add attributes}

View File

@ -236,7 +236,7 @@ implementation
uses
variants, strutils, math, lazutf8, LazFileUtils, uriparser,
{%H-}fpsPatches, fpsCrypto,
{%H-}fpsPatches, fpsCrypto, fpsExprParser,
fpsStrings, fpsStreams, fpsClasses, fpsImages;
const
@ -696,42 +696,52 @@ begin
begin
// Formula to cell
formulaStr := GetNodeValue(datanode);
s := GetAttrValue(datanode, 't');
if s = 'shared' then
begin
// Shared formula
s := GetAttrValue(datanode, 'ref');
if (s <> '') then // This defines the shared formula range
try
s := GetAttrValue(datanode, 't');
if s = 'shared' then
begin
AWorksheet.WriteFormula(cell, formulaStr);
// We store the shared formula base in the SharedFormulaBaseList.
// The list index is identical with the 'si' attribute of the node.
sharedformulabase := TSharedFormulaData.Create;
sharedformulabase.Worksheet := FWorksheet;
sharedformulabase.Row := rowindex;
sharedformulabase.Col := colindex;
sharedformulabase.Formula := formulaStr;
FSharedFormulaBaseList.Add(sharedformulabase);
end else
begin
// Get index into the SharedFormulaBaseList...
s := GetAttrValue(datanode, 'si');
if s <> '' then
// Shared formula
s := GetAttrValue(datanode, 'ref');
if (s <> '') then // This defines the shared formula range
begin
sharedformulabase := TSharedFormulaData(FSharedFormulaBaseList[StrToInt(s)]);
// ... and copy shared formula to destination cell
InitCell(FWorksheet, sharedformulabase.Row, sharedformulabase.Col, lCell);
lCell.Formulavalue := sharedformulabase.Formula;
lCell.Worksheet := sharedformulabase.Worksheet;
FWorksheet.CopyFormula(@lCell, cell);
cell^.ContentType := cctFormula;
AWorksheet.WriteFormula(cell, formulaStr);
// We store the shared formula base in the SharedFormulaBaseList.
// The list index is identical with the 'si' attribute of the node.
sharedformulabase := TSharedFormulaData.Create;
sharedformulabase.Worksheet := FWorksheet;
sharedformulabase.Row := rowindex;
sharedformulabase.Col := colindex;
sharedformulabase.Formula := formulaStr;
FSharedFormulaBaseList.Add(sharedformulabase);
end else
begin
// Get index into the SharedFormulaBaseList...
s := GetAttrValue(datanode, 'si');
if s <> '' then
begin
sharedformulabase := TSharedFormulaData(FSharedFormulaBaseList[StrToInt(s)]);
// ... and copy shared formula to destination cell
InitCell(FWorksheet, sharedformulabase.Row, sharedformulabase.Col, lCell);
lCell.Formulavalue := sharedformulabase.Formula;
lCell.Worksheet := sharedformulabase.Worksheet;
FWorksheet.CopyFormula(@lCell, cell);
cell^.ContentType := cctFormula;
end;
end;
end
else
// "Normal" formula
AWorksheet.WriteFormula(cell, formulaStr);
except
on E:EExprParser do begin
FWorkbook.AddErrorMsg(E.Message);
if (boAbortReadOnFormulaError in Workbook.Options) then raise;
end;
end
else
// "Normal" formula
AWorksheet.WriteFormula(cell, formulaStr);
on E:ECalcEngine do begin
FWorkbook.AddErrorMsg(E.Message);
if (boAbortReadOnFormulaError in Workbook.Options) then raise;
end;
end;
end;
datanode := datanode.NextSibling;
end;