diff --git a/components/fpspreadsheet/examples/read_write/excelxmldemo/excelxmlwrite.lpr b/components/fpspreadsheet/examples/read_write/excelxmldemo/excelxmlwrite.lpr
index 53231d3e4..73984aa2e 100644
--- a/components/fpspreadsheet/examples/read_write/excelxmldemo/excelxmlwrite.lpr
+++ b/components/fpspreadsheet/examples/read_write/excelxmldemo/excelxmlwrite.lpr
@@ -36,7 +36,7 @@ begin
// Create the spreadsheet
MyWorkbook := TsWorkbook.Create;
- MyWorkbook.SetDefaultFont('Calibri', 9);
+ MyWorkbook.SetDefaultFont('Calibri', 10);
MyWorkbook.FormatSettings.CurrencyFormat := 2;
MyWorkbook.FormatSettings.NegCurrFormat := 14;
MyWorkbook.Options := MyWorkbook.Options + [boCalcBeforeSaving];
@@ -138,19 +138,7 @@ begin
MyWorksheet.WriteText(8, 3, 'Colors...');
MyWorksheet.WriteFont(8, 3, 'Courier New', 12, [fssUnderline], scBlue);
MyWorksheet.WriteBackgroundColor(8, 3, scYellow);
-// MyWorksheet.WriteComment(8, 3, 'This is font "Courier New", Size 12.');
-
- {}
- {
- // Uncomment this to test large XLS files
- for i := 50 to 1000 do
- begin
-// MyWorksheet.WriteUTF8Text(i, 0, ParamStr(0));
-// MyWorksheet.WriteUTF8Text(i, 1, ParamStr(0));
-// MyWorksheet.WriteUTF8Text(i, 2, ParamStr(0));
- MyWorksheet.WriteUTF8Text(i, 3, ParamStr(0));
- end;
- }
+ MyWorksheet.WriteComment(8, 3, 'This is font "Courier New", Size 12.');
// Write the string formula E1 = A1 + B1 ...
MyWorksheet.WriteFormula(0, 4, 'A1+B1');
diff --git a/components/fpspreadsheet/fpsexprparser.pas b/components/fpspreadsheet/fpsexprparser.pas
index f0aa96cb7..de243aa9e 100644
--- a/components/fpspreadsheet/fpsexprparser.pas
+++ b/components/fpspreadsheet/fpsexprparser.pas
@@ -80,8 +80,6 @@ type
TsExpressionParser = class;
TsBuiltInExpressionManager = class;
- TsFormulaDialect = (fdExcel, fdOpenDocument);
-
TsResultType = (rtEmpty, rtBoolean, rtInteger, rtFloat, rtDateTime, rtString,
rtCell, rtCellRange, rtHyperlink, rtError, rtMissingArg, rtAny);
TsResultTypes = set of TsResultType;
@@ -1222,7 +1220,7 @@ end;
constructor TsExpressionParser.Create(AWorksheet: TsWorksheet);
begin
inherited Create;
- FDialect := fdExcel;
+ FDialect := fdExcelA1;
FWorksheet := AWorksheet;
FIdentifiers := TsExprIdentifierDefs.Create(TsExprIdentifierDef);
FIdentifiers.FParser := Self;
@@ -3555,9 +3553,16 @@ end;
function TsCellExprNode.AsString: string;
begin
+ case FParser.Dialect of
+ fdExcelA1 : Result := GetCellString(GetRow, GetCol, FFlags);
+ fdExcelR1C1 : Result := GetCellString_R1C1(GetRow, GetCol, FFlags, FParser.FSourceCell^.Row, FParser.FSourceCell^.Col);
+ fdOpenDocument : Result := '[.' + GetCellString(GetRow, GetCol, FFlags) + ']';
+ end;
+ {
Result := GetCellString(GetRow, GetCol, FFlags);
if FParser.Dialect = fdOpenDocument then
Result := '[.' + Result + ']';
+ }
end;
procedure TsCellExprNode.Check;
diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas
index 8206a4fae..2bd0e4df9 100755
--- a/components/fpspreadsheet/fpsopendocument.pas
+++ b/components/fpspreadsheet/fpsopendocument.pas
@@ -1955,12 +1955,12 @@ begin
p := pos('=', formula);
Delete(formula, 1, p);
end;
- // ... convert to Excel dialect used by fps by defailt
+ // ... convert to Excel "A1" dialect used by fps by defailt
parser := TsSpreadsheetParser.Create(FWorksheet);
try
parser.Dialect := fdOpenDocument;
parser.LocalizedExpression[FPointSeparatorSettings] := formula;
- parser.Dialect := fdExcel;
+ parser.Dialect := fdExcelA1;
formula := parser.Expression;
finally
parser.Free;
diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 6b1625c4c..e3c30b747 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -375,6 +375,7 @@ type
function BuildRPNFormula(ACell: PCell; ADestCell: PCell = nil): TsRPNFormula;
procedure CalcFormula(ACell: PCell);
procedure CalcFormulas;
+ function ConvertFormulaDialect(ACell: PCell; ADialect: TsFormulaDialect): String;
function ConvertRPNFormulaToStringFormula(const AFormula: TsRPNFormula): String;
function GetCalcState(ACell: PCell): TsCalcState;
procedure SetCalcState(ACell: PCell; AValue: TsCalcState);
@@ -2675,6 +2676,26 @@ begin
Result := False;
end;
+function TsWorksheet.ConvertFormulaDialect(ACell: PCell;
+ ADialect: TsFormulaDialect): String;
+var
+ parser: TsSpreadsheetParser;
+begin
+ if ACell^.Formulavalue <> '' then
+ begin
+ parser := TsSpreadsheetParser.Create(self);
+ try
+ parser.Expression := ACell^.FormulaValue;
+ parser.Dialect := ADialect;
+ parser.PrepareCopyMode(ACell, ACell);
+ Result := parser.Expression;
+ finally
+ parser.Free;
+ end;
+ end else
+ Result := '';
+end;
+
{@@ ----------------------------------------------------------------------------
Converts an RPN formula (as read from an xls biff file, for example) to a
string formula.
diff --git a/components/fpspreadsheet/fpstypes.pas b/components/fpspreadsheet/fpstypes.pas
index 75b10ba71..379a64a0b 100644
--- a/components/fpspreadsheet/fpstypes.pas
+++ b/components/fpspreadsheet/fpstypes.pas
@@ -143,6 +143,9 @@ type
Simplifies the task of format writers which need RPN }
TsRPNFormula = array of TsFormulaElement;
+ {@@ Formula dialect }
+ TsFormulaDialect = (fdExcelA1, fdExcelR1C1, fdOpenDocument);
+
{@@ Describes the type of content in a cell of a TsWorksheet }
TCellContentType = (cctEmpty, cctFormula, cctNumber, cctUTF8String,
cctDateTime, cctBool, cctError);
diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas
index 6cc416bdd..237b3f30c 100644
--- a/components/fpspreadsheet/fpsutils.pas
+++ b/components/fpspreadsheet/fpsutils.pas
@@ -80,6 +80,9 @@ function GetColString(AColIndex: Integer): String;
function GetCellString(ARow,ACol: Cardinal;
AFlags: TsRelFlags = [rfRelRow, rfRelCol]): String;
+function GetCellString_R1C1(ARow, ACol: Cardinal; AFlags: TsRelFlags = [rfRelRow, rfRelCol];
+ ARefRow: Cardinal = Cardinal(-1); ARefCol: Cardinal = Cardinal(-1)): String;
+
function GetCellRangeString(ARow1, ACol1, ARow2, ACol2: Cardinal;
AFlags: TsRelFlags = rfAllRel; Compact: Boolean = false): String; overload;
function GetCellRangeString(ARange: TsCellRange;
@@ -717,6 +720,46 @@ begin
]);
end;
+{@@ ----------------------------------------------------------------------------
+ Calculates a cell address string in R1C1 notation from zero-based column and
+ row indexes and the relative address state flags.
+
+ @param ARow Zero-based row index
+ @param ACol Zero-based column index
+ @param AFlags An optional set containing an entry for column and row
+ if these addresses are relative. By default, relative
+ addresses are assumed.
+ @param @ARefRow Zero-based row index of the reference cell in case of
+ relative address.
+ @param @ARefCol Zero-based column index of the reference cell in case of
+ relative address.
+ @return Excel type of cell address in R1C1 notation.
+-------------------------------------------------------------------------------}
+function GetCellString_R1C1(ARow, ACol: Cardinal; AFlags: TsRelFlags = [rfRelRow, rfRelCol];
+ ARefRow: Cardinal = Cardinal(-1); ARefCol: Cardinal = Cardinal(-1)): String;
+var
+ delta: LongInt;
+begin
+ if rfRelRow in AFlags then
+ begin
+ delta := LongInt(ARow) - LongInt(ARefRow);
+ if delta = 0 then
+ Result := 'R' else
+ Result := 'R[' + IntToStr(delta) + ']';
+ end else
+ Result := 'R' + IntToStr(ARow+1);
+
+ if rfRelCol in AFlags then
+ begin
+ delta := LongInt(ACol) - LongInt(ARefCol);
+ if delta = 0 then
+ Result := Result + 'C' else
+ Result := Result + 'C[' + IntToStr(delta) + ']';
+ end else
+ Result := Result + 'C' + IntToStr(ACol+1);
+end;
+
+
{@@ ----------------------------------------------------------------------------
Calculates a cell range address string from zero-based column and row indexes
and the relative address state flags.
diff --git a/components/fpspreadsheet/xlsxml.pas b/components/fpspreadsheet/xlsxml.pas
index 66bc47146..d22b34d17 100644
--- a/components/fpspreadsheet/xlsxml.pas
+++ b/components/fpspreadsheet/xlsxml.pas
@@ -1,15 +1,15 @@
-{@@ ----------------------------------------------------------------------------
- Unit: xlsxml
+{-------------------------------------------------------------------------------
+Unit : xlsxml
- implements a reader and writer for the SpreadsheetXML format.
- This document was introduced by Microsoft for Excel XP and 2003.
+Implements a reader and writer for the SpreadsheetXML format.
+This document was introduced by Microsoft for Excel XP and 2003.
- REFERENCE: https://msdn.microsoft.com/en-us/library/aa140066%28v=office.15%29.aspx
+REFERENCE: https://msdn.microsoft.com/en-us/library/aa140066%28v=office.15%29.aspx
- AUTHOR : Werner Pamler
+AUTHOR : Werner Pamler
- LICENSE : See the file COPYING.modifiedLGPL.txt, included in the Lazarus
- distribution, for details about the license.
+LICENSE : For details about the license, see the file
+ COPYING.modifiedLGPL.txt included in the Lazarus distribution.
-------------------------------------------------------------------------------}
unit xlsxml;
@@ -34,6 +34,7 @@ type
FDateMode: TDateMode;
FPointSeparatorSettings: TFormatSettings;
function GetCommentStr(ACell: PCell): String;
+ function GetFormulaStr(ACell: PCell): String;
function GetHyperlinkStr(ACell: PCell): String;
function GetIndexStr(AIndex: Integer): String;
function GetMergeStr(ACell: PCell): String;
@@ -180,6 +181,16 @@ begin
// Result := '