You've already forked lazarus-ccr
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:
@@ -606,6 +606,8 @@ type
|
|||||||
FIsRef: Boolean;
|
FIsRef: Boolean;
|
||||||
protected
|
protected
|
||||||
procedure Check; override;
|
procedure Check; override;
|
||||||
|
function GetCol: Cardinal;
|
||||||
|
function GetRow: Cardinal;
|
||||||
procedure GetNodeValue(var Result: TsExpressionResult); override;
|
procedure GetNodeValue(var Result: TsExpressionResult); override;
|
||||||
public
|
public
|
||||||
constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
|
constructor Create(AParser: TsExpressionParser; AWorksheet: TsWorksheet;
|
||||||
@@ -688,6 +690,7 @@ type
|
|||||||
FDirty: Boolean;
|
FDirty: Boolean;
|
||||||
FWorksheet: TsWorksheet;
|
FWorksheet: TsWorksheet;
|
||||||
FDialect: TsFormulaDialect;
|
FDialect: TsFormulaDialect;
|
||||||
|
FActiveCell: PCell;
|
||||||
procedure CheckEOF;
|
procedure CheckEOF;
|
||||||
procedure CheckNodes(var ALeft, ARight: TsExprNode);
|
procedure CheckNodes(var ALeft, ARight: TsExprNode);
|
||||||
function ConvertNode(Todo: TsExprNode; ToType: TsResultType): TsExprNode;
|
function ConvertNode(Todo: TsExprNode; ToType: TsResultType): TsExprNode;
|
||||||
@@ -738,6 +741,8 @@ type
|
|||||||
function Evaluate: TsExpressionResult;
|
function Evaluate: TsExpressionResult;
|
||||||
procedure EvaluateExpression(var Result: TsExpressionResult);
|
procedure EvaluateExpression(var Result: TsExpressionResult);
|
||||||
function ResultType: TsResultType;
|
function ResultType: TsResultType;
|
||||||
|
function SharedFormulaMode: Boolean;
|
||||||
|
|
||||||
property AsFloat: TsExprFloat read GetAsFloat;
|
property AsFloat: TsExprFloat read GetAsFloat;
|
||||||
property AsInteger: Int64 read GetAsInteger;
|
property AsInteger: Int64 read GetAsInteger;
|
||||||
property AsString: String read GetAsString;
|
property AsString: String read GetAsString;
|
||||||
@@ -750,6 +755,7 @@ type
|
|||||||
property RPNFormula: TsRPNFormula read GetRPNFormula write SetRPNFormula;
|
property RPNFormula: TsRPNFormula read GetRPNFormula write SetRPNFormula;
|
||||||
property Identifiers: TsExprIdentifierDefs read FIdentifiers write SetIdentifiers;
|
property Identifiers: TsExprIdentifierDefs read FIdentifiers write SetIdentifiers;
|
||||||
property BuiltIns: TsBuiltInExprCategories read FBuiltIns write SetBuiltIns;
|
property BuiltIns: TsBuiltInExprCategories read FBuiltIns write SetBuiltIns;
|
||||||
|
property ActiveCell: PCell read FActiveCell write FActiveCell;
|
||||||
property Worksheet: TsWorksheet read FWorksheet;
|
property Worksheet: TsWorksheet read FWorksheet;
|
||||||
property Dialect: TsFormulaDialect read FDialect write FDialect;
|
property Dialect: TsFormulaDialect read FDialect write FDialect;
|
||||||
end;
|
end;
|
||||||
@@ -1974,6 +1980,13 @@ begin
|
|||||||
if Assigned(FExprNode) then FExprNode.Check;
|
if Assigned(FExprNode) then FExprNode.Check;
|
||||||
end;
|
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;
|
function TsExpressionParser.TokenType: TsTokenType;
|
||||||
begin
|
begin
|
||||||
Result := FScanner.TokenType;
|
Result := FScanner.TokenType;
|
||||||
@@ -3775,66 +3788,90 @@ end;
|
|||||||
function TsCellExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem;
|
function TsCellExprNode.AsRPNItem(ANext: PRPNItem): PRPNItem;
|
||||||
begin
|
begin
|
||||||
if FIsRef then
|
if FIsRef then
|
||||||
Result := RPNCellRef(FRow, FCol, FFlags, ANext)
|
Result := RPNCellRef(GetRow, GetCol, FFlags, ANext)
|
||||||
else
|
else
|
||||||
Result := RPNCellValue(FRow, FCol, FFlags, ANext);
|
Result := RPNCellValue(GetRow, GetCol, FFlags, ANext);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsCellExprNode.AsString: string;
|
function TsCellExprNode.AsString: string;
|
||||||
begin
|
begin
|
||||||
Result := GetCellString(FRow, FCol, FFlags);
|
Result := GetCellString(GetRow, GetCol, FFlags);
|
||||||
if FParser.Dialect = fdOpenDocument then
|
if FParser.Dialect = fdOpenDocument then
|
||||||
Result := '[.' + Result + ']';
|
Result := '[.' + Result + ']';
|
||||||
end;
|
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;
|
procedure TsCellExprNode.Check;
|
||||||
begin
|
begin
|
||||||
// Nothing to check;
|
// Nothing to check;
|
||||||
end;
|
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;
|
function TsCellExprNode.NodeType: TsResultType;
|
||||||
begin
|
begin
|
||||||
Result := rtCell;
|
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;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -3621,7 +3621,11 @@ begin
|
|||||||
parser := TsSpreadsheetParser.Create(FWorksheet);
|
parser := TsSpreadsheetParser.Create(FWorksheet);
|
||||||
try
|
try
|
||||||
parser.Dialect := fdOpenDocument;
|
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];
|
formula := Parser.LocalizedExpression[FPointSeparatorSettings];
|
||||||
finally
|
finally
|
||||||
parser.Free;
|
parser.Free;
|
||||||
|
@@ -1760,7 +1760,11 @@ begin
|
|||||||
end;
|
end;
|
||||||
parser := TsSpreadsheetParser.Create(self);
|
parser := TsSpreadsheetParser.Create(self);
|
||||||
try
|
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;
|
Result := parser.RPNFormula;
|
||||||
finally
|
finally
|
||||||
parser.Free;
|
parser.Free;
|
||||||
@@ -1798,6 +1802,7 @@ var
|
|||||||
parser: TsSpreadsheetParser;
|
parser: TsSpreadsheetParser;
|
||||||
res: TsExpressionResult;
|
res: TsExpressionResult;
|
||||||
formula: String;
|
formula: String;
|
||||||
|
cell: PCell;
|
||||||
begin
|
begin
|
||||||
ACell^.CalcState := csCalculating;
|
ACell^.CalcState := csCalculating;
|
||||||
|
|
||||||
@@ -1817,6 +1822,20 @@ begin
|
|||||||
rtDateTime : WriteDateTime(ACell, res.ResDateTime);
|
rtDateTime : WriteDateTime(ACell, res.ResDateTime);
|
||||||
rtString : WriteUTF8Text(ACell, res.ResString);
|
rtString : WriteUTF8Text(ACell, res.ResString);
|
||||||
rtBoolean : WriteBoolValue(ACell, res.ResBoolean);
|
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;
|
end;
|
||||||
finally
|
finally
|
||||||
parser.Free;
|
parser.Free;
|
||||||
|
Reference in New Issue
Block a user