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

View File

@ -2357,10 +2357,25 @@ begin
// ... convert to Excel "A1" dialect used by fps by defailt // ... convert to Excel "A1" dialect used by fps by defailt
parser := TsSpreadsheetParser.Create(FWorksheet); parser := TsSpreadsheetParser.Create(FWorksheet);
try try
parser.Dialect := fdOpenDocument; try
parser.LocalizedExpression[FPointSeparatorSettings] := formula; parser.Dialect := fdOpenDocument;
parser.Dialect := fdExcelA1; parser.LocalizedExpression[FPointSeparatorSettings] := formula;
formula := parser.Expression; 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 finally
parser.Free; parser.Free;
end; end;

View File

@ -654,8 +654,8 @@ type
@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
cells but passed the the event OnReadCellData; as 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
@ -663,19 +663,22 @@ type
@param boFileStream Uses file streams and temporary files during @param boFileStream Uses file streams and temporary files during
reading and writing. Lowest memory consumptions, reading and writing. Lowest memory consumptions,
but slow. but slow.
@param boAutoCalc Automatically recalculate rpn formulas whenever @param boAutoCalc Automatically recalculate formulas whenever a
a cell value changes. cell value changes.
@param boCalcBeforeSaving Calculates formulas before saving the file. @param boCalcBeforeSaving Calculates formulas before saving the file.
Otherwise there are no results when the file is Otherwise there are no results when the file is
loaded back by fpspreadsheet. loaded back by fpspreadsheet.
@param boReadFormulas Allows to turn off reading of rpn formulas; this is @param boReadFormulas Allows to turn off reading of rpn formulas; this
a precaution since formulas not correctly is a precaution since formulas not correctly
implemented by fpspreadsheet could crash the implemented by fpspreadsheet could crash the
reading operation. reading operation.
@param boWriteZoomfactor Instructs the writer to write the current zoom @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, TsWorkbookOption = (boVirtualMode, boBufStream, boFileStream,
boAutoCalc, boCalcBeforeSaving, boReadFormulas, boWriteZoomFactor); boAutoCalc, boCalcBeforeSaving, boReadFormulas, boWriteZoomFactor,
boAbortReadOnFormulaError);
{@@ Set of option flags for the workbook } {@@ Set of option flags for the workbook }
TsWorkbookOptions = set of TsWorkbookOption; TsWorkbookOptions = set of TsWorkbookOption;

View File

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

View File

@ -1662,6 +1662,7 @@ var
err: TsErrorValue; err: TsErrorValue;
ok: Boolean; ok: Boolean;
cell: PCell; cell: PCell;
msg: String;
begin begin
{ Index to XF Record } { Index to XF Record }
ReadRowColXF(AStream, ARow, ACol, XF); ReadRowColXF(AStream, ARow, ACol, XF);
@ -1720,7 +1721,17 @@ begin
begin begin
ok := ReadRPNTokenArray(AStream, cell); ok := ReadRPNTokenArray(AStream, cell);
if not ok then 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; end;
{Add attributes} {Add attributes}

View File

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