fpspreadsheet: Writing of shared formulas for ods and biff2 (shared formulas are not yet working in the other formats).

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3522 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-09-03 21:12:20 +00:00
parent 25fbced80c
commit ef0a0319db
3 changed files with 105 additions and 45 deletions

View File

@@ -606,6 +606,8 @@ type
FIsRef: Boolean;
protected
procedure Check; override;
function GetCol: Cardinal;
function GetRow: Cardinal;
procedure GetNodeValue(var Result: TsExpressionResult); override;
public
constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
@@ -688,6 +690,7 @@ type
FDirty: Boolean;
FWorksheet: TsWorksheet;
FDialect: TsFormulaDialect;
FActiveCell: PCell;
procedure CheckEOF;
procedure CheckNodes(var ALeft, ARight: TsExprNode);
function ConvertNode(Todo: TsExprNode; ToType: TsResultType): TsExprNode;
@@ -738,6 +741,8 @@ type
function Evaluate: TsExpressionResult;
procedure EvaluateExpression(var Result: TsExpressionResult);
function ResultType: TsResultType;
function SharedFormulaMode: Boolean;
property AsFloat: TsExprFloat read GetAsFloat;
property AsInteger: Int64 read GetAsInteger;
property AsString: String read GetAsString;
@@ -750,6 +755,7 @@ 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 FDialect;
end;
@@ -1974,6 +1980,13 @@ begin
if Assigned(FExprNode) then FExprNode.Check;
end;
{ Signals that the parser is in SharedFormulaMode, i.e. there is an active cell
to which all relative addresses have to be adapted. }
function TsExpressionParser.SharedFormulaMode: Boolean;
begin
Result := (ActiveCell <> nil) and (ActiveCell^.SharedFormulaBase <> nil);
end;
function TsExpressionParser.TokenType: TsTokenType;
begin
Result := FScanner.TokenType;
@@ -3775,66 +3788,90 @@ end;
function TsCellExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem;
begin
if FIsRef then
Result := RPNCellRef(FRow, FCol, FFlags, ANext)
Result := RPNCellRef(GetRow, GetCol, FFlags, ANext)
else
Result := RPNCellValue(FRow, FCol, FFlags, ANext);
Result := RPNCellValue(GetRow, GetCol, FFlags, ANext);
end;
function TsCellExprNode.AsString: string;
begin
Result := GetCellString(FRow, FCol, FFlags);
Result := GetCellString(GetRow, GetCol, FFlags);
if FParser.Dialect = fdOpenDocument then
Result := '[.' + Result + ']';
end;
procedure TsCellExprNode.GetNodeValue(var Result: TsExpressionResult);
begin
if (FCell <> nil) and HasFormula(FCell) then
case FCell^.CalcState of
csNotCalculated:
Worksheet.CalcFormula(FCell);
csCalculating:
raise Exception.Create(SErrCircularReference);
end;
Result.ResultType := rtCell;
Result.ResRow := FRow;
Result.ResCol := FCol;
Result.Worksheet := FWorksheet;
end;
procedure TsCellExprNode.Check;
begin
// Nothing to check;
end;
{ Calculates the row address of the node's cell for various cases:
(1) SharedFormula mode:
The "ActiveCell" of the parser is the cell for which the formula is
calculated. If the formula contains a relative address in the cell node
the function calculates the row address of the cell represented by the
node as seen from the active cell.
If the formula contains an absolute address the function returns the row
address of the SharedFormulaBase of the ActiveCell.
(2) Normal mode:
Returns the "true" row address of the cell assigned to the formula node. }
function TsCellExprNode.GetCol: Cardinal;
begin
if FParser.SharedFormulaMode then
begin
// A shared formula is stored in the SharedFormulaBase cell of the ActiveCell
// Since the cell data stored in the node are those used by the formula in
// the SharedFormula, the current node is relative to the SharedFormulaBase
if rfRelCol in FFlags then
Result := FCol - FParser.ActiveCell^.SharedFormulaBase^.Col + FParser.ActiveCell^.Col
else
Result := FParser.ActiveCell^.SharedFormulaBase^.Col;
end
else
// Normal mode
Result := FCol;
end;
procedure TsCellExprNode.GetNodeValue(var Result: TsExpressionResult);
var
cell: PCell;
begin
if Parser.SharedFormulaMode then
cell := FWorksheet.FindCell(GetRow, GetCol)
else
cell := FCell;
if (cell <> nil) and HasFormula(cell) then
case cell^.CalcState of
csNotCalculated:
Worksheet.CalcFormula(cell);
csCalculating:
raise Exception.Create(SErrCircularReference);
end;
Result.ResultType := rtCell;
Result.ResRow := GetRow;
Result.ResCol := GetCol;
Result.Worksheet := FWorksheet;
end;
{ See GetCol }
function TsCellExprNode.GetRow: Cardinal;
begin
if Parser.SharedFormulaMode then
begin
if rfRelRow in FFlags then
Result := FRow - FParser.ActiveCell^.SharedFormulaBase^.Row + FParser.ActiveCell^.Row
else
Result := FParser.ActiveCell^.SharedFormulaBase^.Row;
end
else
Result := FRow;
end;
function TsCellExprNode.NodeType: TsResultType;
begin
Result := rtCell;
{
if FIsRef then
Result := rtCell
else
begin
Result := rtEmpty;
if FCell <> nil then
case FCell^.ContentType of
cctNumber:
if frac(FCell^.NumberValue) = 0 then
Result := rtInteger
else
Result := rtFloat;
cctDateTime:
Result := rtDateTime;
cctUTF8String:
Result := rtString;
cctBool:
Result := rtBoolean;
cctError:
Result := rtError;
end;
end;
}
end;

View File

@@ -3621,7 +3621,11 @@ begin
parser := TsSpreadsheetParser.Create(FWorksheet);
try
parser.Dialect := fdOpenDocument;
parser.Expression := ACell^.FormulaValue;
if ACell^.SharedFormulaBase <> nil then begin
parser.ActiveCell := ACell;
parser.Expression := ACell^.SharedFormulaBase^.FormulaValue;
end else
parser.Expression := ACell^.FormulaValue;
formula := Parser.LocalizedExpression[FPointSeparatorSettings];
finally
parser.Free;

View File

@@ -1760,7 +1760,11 @@ begin
end;
parser := TsSpreadsheetParser.Create(self);
try
parser.Expression := ACell^.FormulaValue;
if (ACell^.SharedFormulaBase <> nil) then begin
parser.ActiveCell := ACell;
parser.Expression := ACell^.SharedFormulaBase^.FormulaValue;
end else
parser.Expression := ACell^.FormulaValue;
Result := parser.RPNFormula;
finally
parser.Free;
@@ -1798,6 +1802,7 @@ var
parser: TsSpreadsheetParser;
res: TsExpressionResult;
formula: String;
cell: PCell;
begin
ACell^.CalcState := csCalculating;
@@ -1817,6 +1822,20 @@ begin
rtDateTime : WriteDateTime(ACell, res.ResDateTime);
rtString : WriteUTF8Text(ACell, res.ResString);
rtBoolean : WriteBoolValue(ACell, res.ResBoolean);
rtCell : begin
cell := FindCell(res.ResRow, res.ResCol);
if cell = nil then
WriteBlank(ACell)
else
case cell^.ContentType of
cctNumber : WriteNumber(ACell, cell^.NumberValue);
cctDateTime : WriteDateTime(ACell, cell^.DateTimeValue);
cctUTF8String: WriteUTF8Text(ACell, cell^.UTF8StringValue);
cctBool : WriteBoolValue(ACell, cell^.Boolvalue);
cctError : WriteErrorValue(ACell, cell^.ErrorValue);
cctEmpty : WriteBlank(ACell);
end;
end;
end;
finally
parser.Free;