diff --git a/components/fpspreadsheet/examples/other/demo_ignore_formula.lpi b/components/fpspreadsheet/examples/other/demo_ignore_formula.lpi
new file mode 100644
index 000000000..b1fb06da7
--- /dev/null
+++ b/components/fpspreadsheet/examples/other/demo_ignore_formula.lpi
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/other/demo_ignore_formula.lpr b/components/fpspreadsheet/examples/other/demo_ignore_formula.lpr
new file mode 100644
index 000000000..5c01752b2
--- /dev/null
+++ b/components/fpspreadsheet/examples/other/demo_ignore_formula.lpr
@@ -0,0 +1,114 @@
+{ This example uses the "ignoreFormula" workbook option to create an ods
+ file with an external reference.
+
+ NOTE: The external reference is not calculated. This will happen when
+ LibreOffice Calc loads the file. When the file is closed in LOCalc
+ confirmation must be given to save the file because it has been changed
+ by LOCalc.
+
+ This method does not work with Excel because it writes an additonal
+ folder and xml files for external links. }
+
+program demo_ignore_formula;
+
+{$mode objfpc}{$H+}
+
+{$DEFINE ODS}
+{.$DEFINE XLSX} // <---- NOT WORKING
+
+uses
+ SysUtils, FileUtil,
+ fpsTypes, fpsUtils, fpSpreadsheet, fpsOpenDocument, xlsxOOXML;
+
+const
+ {$IFDEF ODS}
+ FILE_FORMAT = sfOpenDocument;
+ MASTER_FILE = 'master.ods';
+ EXTERNAL_FILE = 'external.ods';
+ {$ENDIF}
+ {$IFDEF XLSX}
+ FILE_FORMAT = sfOOXML;
+ MASTER_FILE = 'master.xlsx';
+ EXTERNAL_FILE = 'external.xlsx';
+ {$ENDIF}
+ EXTERNAL_SHEET = 'Sheet';
+ CELL1 = 'A1';
+ CELL2 = 'B1';
+
+
+var
+ book: TsWorkbook;
+ sheet: TsWorksheet;
+ cell: PCell;
+
+ // example for an external ods reference:
+ // ='file:///D:/fpspreadsheet/examples/other/external.ods'#$Sheet.A1
+ function ODS_ExtRef(AFilename, ASheetName, ACellAddr: String): String;
+ var
+ i: Integer;
+ begin
+ Result := ExpandFileName(AFileName);
+ for i:=1 to Length(Result) do
+ if Result[i] = '\' then Result[i] := '/';
+ Result := Format('''file:///%s''#$%s.%s', [
+ Result, ASheetName, ACellAddr
+ ]);
+ end;
+
+ // example for an external xlsx reference:
+ // =[external.xlsx]Sheet!$A$1
+ function XLSX_ExtRef(AFilename, ASheetName, ACellAddr: String): String;
+ var
+ r, c: Cardinal;
+ flags: TsRelFlags;
+ begin
+ ParseCellString(ACellAddr, r, c, flags);
+ Result := Format('[%s]%s!%s', [
+ ExtractFileName(AFileName), ASheetName, GetCellString(r, c, [])
+ ]);
+ end;
+
+ function ExtRef(AFileName, ASheetName, ACellAddr: String): String;
+ begin
+ {$IFDEF ODS}
+ Result := ODS_ExtRef(AFileName, ASheetName, ACellAddr);
+ {$ENDIF}
+ {$IFDEF XLSX}
+ Result := XLSX_ExtRef(AFilename, ASheetName, ACellAddr);
+ {$ENDIF}
+ end;
+
+begin
+ // Write external file
+ book := TsWorkbook.Create;
+ try
+ sheet := book.AddWorksheet(EXTERNAL_SHEET);
+
+ cell := sheet.GetCell(CELL1);
+ sheet.WriteNumber(cell, 1000.0);
+
+ cell := sheet.GetCell(CELL2);
+ sheet.WriteText(cell, 'Hallo');
+
+ book.WriteToFile(EXTERNAL_FILE, FILE_FORMAT, true);
+ finally
+ book.Free;
+ end;
+
+ // Write ods and xlsx master files
+ book := TsWorkbook.Create;
+ try
+ // Instruct fpspreadsheet to leave the formula alone.
+ book.Options := book.Options + [boIgnoreFormulas];
+ sheet := book.AddWorksheet('Sheet');
+
+ // Write external references
+ sheet.WriteFormula(0, 0, ExtRef(EXTERNAL_FILE, EXTERNAL_SHEET, CELL1));
+ sheet.WriteFormula(1, 0, ExtRef(EXTERNAL_FILE, EXTERNAL_SHEET, CELL2));
+ book.WriteToFile(MASTER_FILE, FILE_FORMAT, true);
+
+ finally
+ book.Free;
+ end;
+end.
+
diff --git a/components/fpspreadsheet/source/common/fpsopendocument.pas b/components/fpspreadsheet/source/common/fpsopendocument.pas
index b900ec83e..9cdc44634 100644
--- a/components/fpspreadsheet/source/common/fpsopendocument.pas
+++ b/components/fpspreadsheet/source/common/fpsopendocument.pas
@@ -7446,8 +7446,10 @@ var
comment: String;
r1,c1,r2,c2: Cardinal;
fmt: TsCellFormat;
+ ignoreFormulas: Boolean;
begin
Unused(ARow, ACol);
+ ignoreFormulas := (boIgnoreFormulas in FWorkbook.Options);
// Style
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
@@ -7473,59 +7475,65 @@ begin
if FWorksheet.HasHyperlink(ACell) then
FWorkbook.AddErrorMsg(rsODSHyperlinksOfTextCellsOnly, [GetCellString(ARow, ACol)]);
- // Convert string formula to the format needed by ods: semicolon list separators!
- parser := TsSpreadsheetParser.Create(FWorksheet);
- try
- parser.Dialect := fdOpenDocument;
- parser.Expression := ACell^.FormulaValue;
- formula := Parser.LocalizedExpression[FPointSeparatorSettings];
- finally
- parser.Free;
- end;
+ if ignoreFormulas then begin
+ formula := ACell^.FormulaValue;
+ if (formula <> '') and (formula[1] = '=') then Delete(formula, 1, 1);
+ end else
+ begin
+ valueStr := '';
+ // Convert string formula to the format needed by ods: semicolon list separators!
+ parser := TsSpreadsheetParser.Create(FWorksheet);
+ try
+ parser.Dialect := fdOpenDocument;
+ parser.Expression := ACell^.FormulaValue;
+ formula := Parser.LocalizedExpression[FPointSeparatorSettings];
+ finally
+ parser.Free;
+ end;
- valueStr := '';
- case ACell^.ContentType of
- cctNumber:
- begin
- valuetype := 'float';
- value := ' office:value="' + Format('%g', [ACell^.NumberValue], FPointSeparatorSettings) + '"';
- end;
- cctDateTime:
- if trunc(ACell^.DateTimeValue) = 0 then
- begin
- valuetype := 'time';
- value := ' office:time-value="' + FormatDateTime(ISO8601FormatTimeOnly, ACell^.DateTimeValue) + '"';
- end
- else
- begin
- valuetype := 'date';
- if frac(ACell^.DateTimeValue) = 0.0 then
- value := ' office:date-value="' + FormatDateTime(ISO8601FormatDateOnly, ACell^.DateTimeValue) + '"'
+ case ACell^.ContentType of
+ cctNumber:
+ begin
+ valuetype := 'float';
+ value := ' office:value="' + Format('%g', [ACell^.NumberValue], FPointSeparatorSettings) + '"';
+ end;
+ cctDateTime:
+ if trunc(ACell^.DateTimeValue) = 0 then
+ begin
+ valuetype := 'time';
+ value := ' office:time-value="' + FormatDateTime(ISO8601FormatTimeOnly, ACell^.DateTimeValue) + '"';
+ end
else
- value := ' office:date-value="' + FormatDateTime(ISO8601FormatExtended, ACell^.DateTimeValue) + '"';
- end;
- cctUTF8String:
- begin
- valuetype := 'string';
- value := ' office:string-value="' + ACell^.UTF8StringValue +'"';
- valueStr := '' + ACell^.UTF8StringValue + '';
- end;
- cctBool:
- begin
- valuetype := 'boolean';
- value := ' office:boolean-value="' + BoolToStr(ACell^.BoolValue, 'true', 'false') + '"';
- end;
- cctError:
- if HasFormula(ACell) then
- begin
- // Open/LibreOffice always writes a float value 0 to the cell
- valuetype := 'float'; // error as result of a formula
- value := ' office:value="0"';
- end else
- begin
- valuetype := 'string" calcext:value-type="error'; // an error "constant"
- value := ' office:value=""';
- end;
+ begin
+ valuetype := 'date';
+ if frac(ACell^.DateTimeValue) = 0.0 then
+ value := ' office:date-value="' + FormatDateTime(ISO8601FormatDateOnly, ACell^.DateTimeValue) + '"'
+ else
+ value := ' office:date-value="' + FormatDateTime(ISO8601FormatExtended, ACell^.DateTimeValue) + '"';
+ end;
+ cctUTF8String:
+ begin
+ valuetype := 'string';
+ value := ' office:string-value="' + ACell^.UTF8StringValue +'"';
+ valueStr := '' + ACell^.UTF8StringValue + '';
+ end;
+ cctBool:
+ begin
+ valuetype := 'boolean';
+ value := ' office:boolean-value="' + BoolToStr(ACell^.BoolValue, 'true', 'false') + '"';
+ end;
+ cctError:
+ if HasFormula(ACell) then
+ begin
+ // Open/LibreOffice always writes a float value 0 to the cell
+ valuetype := 'float'; // error as result of a formula
+ value := ' office:value="0"';
+ end else
+ begin
+ valuetype := 'string" calcext:value-type="error'; // an error "constant"
+ value := ' office:value=""';
+ end;
+ end;
end;
{ Fix special xml characters }
@@ -7533,7 +7541,7 @@ begin
{ We are writing a very rudimentary formula here without result and result
data type. Seems to work... }
- if FWorksheet.GetCalcState(ACell) = csCalculated then
+ if not ignoreFormulas or (FWorksheet.GetCalcState(ACell) = csCalculated) then
AppendToStream(AStream, Format(
'' +
comment +
diff --git a/components/fpspreadsheet/source/common/fpspreadsheet.pas b/components/fpspreadsheet/source/common/fpspreadsheet.pas
index d14109524..a6e32baeb 100644
--- a/components/fpspreadsheet/source/common/fpspreadsheet.pas
+++ b/components/fpspreadsheet/source/common/fpspreadsheet.pas
@@ -675,10 +675,12 @@ type
@param boWriteZoomfactor Instructs the writer to write the current zoom
factors of the worksheets to file.
@param boAbortReadOnFormulaError Aborts reading if a formula error is
- encountered }
+ encountered
+ @param boIgnoreFormulas Formulas are not checked and not calculated.
+ Cannot be used for biff formats. }
TsWorkbookOption = (boVirtualMode, boBufStream, boFileStream,
boAutoCalc, boCalcBeforeSaving, boReadFormulas, boWriteZoomFactor,
- boAbortReadOnFormulaError);
+ boAbortReadOnFormulaError, boIgnoreFormulas);
{@@ Set of option flags for the workbook }
TsWorkbookOptions = set of TsWorkbookOption;
@@ -1273,6 +1275,9 @@ var
cell: PCell;
formula: String;
begin
+ if (boIgnoreFormulas in Workbook.Options) then
+ exit;
+
formula := ACell^.FormulaValue;
ACell^.Flags := ACell^.Flags + [cfCalculating] - [cfCalculated];
@@ -1345,6 +1350,9 @@ procedure TsWorksheet.CalcFormulas;
var
cell: PCell;
begin
+ if (boIgnoreFormulas in Workbook.Options) then
+ exit;
+
// prevent infinite loop due to triggering of formula calculation whenever
// a cell changes during execution of CalcFormulas.
inc(FWorkbook.FCalculationLock);
@@ -5669,18 +5677,21 @@ begin
if ACell = nil then
exit;
- // Remove '='; is not stored internally
- if (AFormula <> '') and (AFormula[1] = '=') then
- AFormula := Copy(AFormula, 2, Length(AFormula));
+ if not (boIgnoreFormulas in Workbook.Options) then
+ begin
+ // Remove '='; is not stored internally
+ if (AFormula <> '') and (AFormula[1] = '=') then
+ AFormula := Copy(AFormula, 2, Length(AFormula));
- // Convert "localized" formula to standard format
- if ALocalized then begin
- parser := TsSpreadsheetParser.Create(self);
- try
- parser.LocalizedExpression[Workbook.FormatSettings] := AFormula;
- AFormula := parser.Expression;
- finally
- parser.Free;
+ // Convert "localized" formula to standard format
+ if ALocalized then begin
+ parser := TsSpreadsheetParser.Create(self);
+ try
+ parser.LocalizedExpression[Workbook.FormatSettings] := AFormula;
+ AFormula := parser.Expression;
+ finally
+ parser.Free;
+ end;
end;
end;