You've already forked lazarus-ccr
fpspreadsheet: Reduce support for shared formulas (too many problems...), only reading from xls and xlsx files supported.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3998 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -63,16 +63,6 @@ begin
|
||||
RPNNumber(5.0,
|
||||
RPNFunc(fekAdd,
|
||||
nil)))));
|
||||
(*
|
||||
// Write a shared formula "=E1+100" to the cell range F1:F5
|
||||
// Please note that shared formulas are not written by sfOOXML and sfOpenDocument formats.
|
||||
MyCell := MyWorksheet.WriteRPNFormula(0, 5, CreateRPNFormula(
|
||||
RPNCellOffset(0, -1, [rfRelRow, rfRelCol],
|
||||
RPNNumber(100,
|
||||
RPNFunc(fekAdd,
|
||||
nil)))));
|
||||
MyWorksheet.UseSharedFormula('F1:F5', MyCell);
|
||||
*)
|
||||
end;
|
||||
|
||||
procedure WriteSecondWorksheet();
|
||||
|
@ -5,7 +5,7 @@ unit fpsclasses;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, AVL_Tree, avglvltree,
|
||||
Classes, SysUtils, AVL_Tree, //avglvltree,
|
||||
fpstypes;
|
||||
|
||||
type
|
||||
@ -175,7 +175,8 @@ type
|
||||
implementation
|
||||
|
||||
uses
|
||||
Math, fpsUtils;
|
||||
{%H-}Math,
|
||||
fpsUtils;
|
||||
|
||||
|
||||
{ Helper function for sorting }
|
||||
@ -233,9 +234,6 @@ begin
|
||||
end;
|
||||
|
||||
function TsRowColEnumerator.MoveNext: Boolean;
|
||||
var
|
||||
r1,c1,r2,c2: Cardinal;
|
||||
item: TsRowCol;
|
||||
begin
|
||||
if FCurrentNode <> nil then begin
|
||||
if FReverse then
|
||||
|
@ -602,8 +602,8 @@ end;
|
||||
|
||||
procedure TsCSVWriter.WriteSheet(AStream: TStream; AWorksheet: TsWorksheet);
|
||||
var
|
||||
r, c: Cardinal;
|
||||
LastRow, LastCol: Cardinal;
|
||||
r: Cardinal;
|
||||
LastRow: Cardinal;
|
||||
cell: PCell;
|
||||
begin
|
||||
FWorksheet := AWorksheet;
|
||||
@ -616,23 +616,12 @@ begin
|
||||
FCSVBuilder.SetOutput(AStream);
|
||||
|
||||
LastRow := FWorksheet.GetLastOccupiedRowIndex;
|
||||
LastCol := FWorksheet.GetLastOccupiedColIndex;
|
||||
for r := 0 to LastRow do
|
||||
begin
|
||||
for cell in FWorksheet.Cells.GetRowEnumerator(r) do
|
||||
WriteCellToStream(AStream, cell);
|
||||
FCSVBuilder.AppendRow;
|
||||
end;
|
||||
{
|
||||
for c := 0 to LastCol do
|
||||
begin
|
||||
Cell := FWorksheet.FindCell(r, c);
|
||||
if Cell <> nil then
|
||||
WriteCellCallback(Cell, AStream);
|
||||
if c = LastCol then
|
||||
FCSVBuilder.AppendRow;
|
||||
end;
|
||||
}
|
||||
finally
|
||||
FreeAndNil(FCSVBuilder);
|
||||
end;
|
||||
|
@ -682,7 +682,9 @@ type
|
||||
FDirty: Boolean;
|
||||
FWorksheet: TsWorksheet;
|
||||
FDialect: TsFormulaDialect;
|
||||
FActiveCell: PCell;
|
||||
FSourceCell: PCell;
|
||||
FDestCell: PCell;
|
||||
// FActiveCell: PCell;
|
||||
procedure CheckEOF;
|
||||
procedure CheckNodes(var ALeft, ARight: TsExprNode);
|
||||
function ConvertNode(Todo: TsExprNode; ToType: TsResultType): TsExprNode;
|
||||
@ -730,10 +732,11 @@ type
|
||||
destructor Destroy; override;
|
||||
function IdentifierByName(AName: ShortString): TsExprIdentifierDef; virtual;
|
||||
procedure Clear;
|
||||
function CopyMode: Boolean;
|
||||
function Evaluate: TsExpressionResult;
|
||||
procedure EvaluateExpression(out Result: TsExpressionResult);
|
||||
procedure PrepareCopyMode(ASourceCell, ADestCell: PCell);
|
||||
function ResultType: TsResultType;
|
||||
function SharedFormulaMode: Boolean;
|
||||
|
||||
property AsFloat: TsExprFloat read GetAsFloat;
|
||||
property AsInteger: Int64 read GetAsInteger;
|
||||
@ -747,7 +750,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 ActiveCell: PCell read FActiveCell write FActiveCell;
|
||||
property Worksheet: TsWorksheet read FWorksheet;
|
||||
property Dialect: TsFormulaDialect read FDialect write FDialect;
|
||||
end;
|
||||
@ -1299,6 +1302,22 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Prepares copy mode: The formula is contained in ASourceCell and will be
|
||||
modified such as seen from ADestCell. }
|
||||
procedure TsExpressionParser.PrepareCopyMode(ASourceCell, ADestCell: PCell);
|
||||
begin
|
||||
FSourceCell := ASourceCell;
|
||||
FDestCell := ADestCell;
|
||||
end;
|
||||
|
||||
{ Signals that the parser is in "CopyMode", i.e. there is are source and
|
||||
destination cells. All relative references in the formula of the source cell
|
||||
habe to be adapted as seen from the destination cell. }
|
||||
function TsExpressionParser.CopyMode: Boolean;
|
||||
begin
|
||||
Result := (FDestCell <> nil) and (FSourceCell <> nil);
|
||||
end;
|
||||
|
||||
procedure TsExpressionParser.CreateHashList;
|
||||
var
|
||||
ID: TsExprIdentifierDef;
|
||||
@ -1975,14 +1994,14 @@ begin
|
||||
CreateNodeFromRPN(FExprNode, index);
|
||||
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;
|
||||
@ -3811,37 +3830,27 @@ begin
|
||||
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.
|
||||
(1) Copy mode:
|
||||
The "DestCell" of the parser is the cell for which the formula is
|
||||
calculated. The "SourceCell" contains the formula. 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 DestCell.
|
||||
If the formula contains an absolute address the function returns the row
|
||||
address of the SharedFormulaBase of the ActiveCell.
|
||||
address of the SourceCell.
|
||||
(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 := FCol; //FParser.ActiveCell^.SharedFormulaBase^.Col;
|
||||
end
|
||||
else
|
||||
// Normal mode
|
||||
Result := FCol;
|
||||
Result := FCol;
|
||||
if FParser.CopyMode and (rfRelCol in FFlags) then
|
||||
Result := FCol - FParser.FSourceCell^.Col + FParser.FDestCell^.Col;
|
||||
end;
|
||||
|
||||
procedure TsCellExprNode.GetNodeValue(out Result: TsExpressionResult);
|
||||
var
|
||||
cell: PCell;
|
||||
begin
|
||||
if Parser.SharedFormulaMode then
|
||||
if Parser.CopyMode then
|
||||
cell := FWorksheet.FindCell(GetRow, GetCol)
|
||||
else
|
||||
cell := FCell;
|
||||
@ -3863,15 +3872,9 @@ 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 := FRow; //FParser.ActiveCell^.SharedFormulaBase^.Row;
|
||||
end
|
||||
else
|
||||
Result := FRow;
|
||||
Result := FRow;
|
||||
if Parser.CopyMode and (rfRelRow in FFlags) then
|
||||
Result := FRow - FParser.FSourceCell^.Row + FParser.FDestCell^.Row;
|
||||
end;
|
||||
|
||||
function TsCellExprNode.NodeType: TsResultType;
|
||||
@ -3998,7 +4001,6 @@ end;
|
||||
function ArgToInt(Arg: TsExpressionResult): Integer;
|
||||
var
|
||||
cell: PCell;
|
||||
s: String;
|
||||
begin
|
||||
Result := 0;
|
||||
case Arg.ResultType of
|
||||
|
@ -4058,11 +4058,13 @@ begin
|
||||
parser := TsSpreadsheetParser.Create(FWorksheet);
|
||||
try
|
||||
parser.Dialect := fdOpenDocument;
|
||||
{
|
||||
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
|
||||
|
@ -234,11 +234,6 @@ type
|
||||
procedure WriteRPNFormula(ACell: PCell;
|
||||
AFormula: TsRPNFormula); overload;
|
||||
|
||||
procedure WriteSharedFormula(ARow1, ACol1, ARow2, ACol2: Cardinal;
|
||||
const AFormula: String); overload;
|
||||
procedure WriteSharedFormula(ACellRange: String;
|
||||
const AFormula: String); overload;
|
||||
|
||||
function WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring): PCell; overload;
|
||||
procedure WriteUTF8Text(ACell: PCell; AText: ansistring); overload;
|
||||
|
||||
@ -330,15 +325,10 @@ type
|
||||
procedure WriteWordwrap(ACell: PCell; AValue: boolean); overload;
|
||||
|
||||
{ Formulas }
|
||||
function BuildRPNFormula(ACell: PCell): TsRPNFormula;
|
||||
function BuildRPNFormula(ACell: PCell; ADestCell: PCell = nil): TsRPNFormula;
|
||||
procedure CalcFormula(ACell: PCell);
|
||||
procedure CalcFormulas;
|
||||
function ConvertRPNFormulaToStringFormula(const AFormula: TsRPNFormula): String;
|
||||
function FindSharedFormulaBase(ACell: PCell): PCell;
|
||||
function FindSharedFormulaRange(ACell: PCell; out ARow1, ACol1, ARow2, ACol2: Cardinal): Boolean;
|
||||
procedure FixSharedFormulas;
|
||||
procedure SplitSharedFormula(ACell: PCell);
|
||||
function UseSharedFormula(ARow, ACol: Cardinal; ASharedFormulaBase: PCell): PCell;
|
||||
function GetCalcState(ACell: PCell): TsCalcState;
|
||||
procedure SetCalcState(ACell: PCell; AValue: TsCalcState);
|
||||
|
||||
@ -586,7 +576,6 @@ type
|
||||
FFontList: TFPList;
|
||||
|
||||
{ Internal methods }
|
||||
procedure FixSharedFormulas;
|
||||
procedure GetLastRowColIndex(out ALastRow, ALastCol: Cardinal);
|
||||
procedure PrepareBeforeReading;
|
||||
procedure PrepareBeforeSaving;
|
||||
@ -979,15 +968,13 @@ begin
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Returns TRUE if the cell contains a formula (direct or shared, does not matter).
|
||||
Returns TRUE if the cell contains a formula.
|
||||
|
||||
@param ACell Pointer to the cell checked
|
||||
-------------------------------------------------------------------------------}
|
||||
function HasFormula(ACell: PCell): Boolean;
|
||||
begin
|
||||
Result := Assigned(ACell) and (
|
||||
(ACell^.SharedFormulaBase <> nil) or (Length(ACell^.FormulaValue) > 0)
|
||||
);
|
||||
Result := Assigned(ACell) and (Length(ACell^.FormulaValue) > 0);
|
||||
end;
|
||||
|
||||
function CompareCells(Item1, Item2: Pointer): Integer;
|
||||
@ -1108,11 +1095,14 @@ end;
|
||||
Helper function which constructs an rpn formula from the cell's string
|
||||
formula. This is needed, for example, when writing a formula to xls biff
|
||||
file format.
|
||||
If the cell belongs to a shared formula the formula is taken from the
|
||||
shared formula base cell, cell references are adapted accordingly to the
|
||||
location of the cell.
|
||||
The formula is stored in ACell.
|
||||
If ADestCell is not nil then the relative references are adjusted as seen
|
||||
from ADestCell. This means that this function returns the formula that
|
||||
would be created if ACell is copied to the location of ADestCell.
|
||||
Needed for copying formulas and for splitting shared formulas.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsWorksheet.BuildRPNFormula(ACell: PCell): TsRPNFormula;
|
||||
function TsWorksheet.BuildRPNFormula(ACell: PCell;
|
||||
ADestCell: PCell = nil): TsRPNFormula;
|
||||
var
|
||||
parser: TsSpreadsheetParser;
|
||||
begin
|
||||
@ -1122,11 +1112,9 @@ begin
|
||||
end;
|
||||
parser := TsSpreadsheetParser.Create(self);
|
||||
try
|
||||
if (ACell^.SharedFormulaBase <> nil) then begin
|
||||
parser.ActiveCell := ACell;
|
||||
parser.Expression := ACell^.SharedFormulaBase^.FormulaValue;
|
||||
end else
|
||||
parser.Expression := ACell^.FormulaValue;
|
||||
if ADestCell <> nil then
|
||||
parser.PrepareCopyMode(ACell, ADestCell);
|
||||
parser.Expression := ACell^.FormulaValue;
|
||||
Result := parser.RPNFormula;
|
||||
finally
|
||||
parser.Free;
|
||||
@ -1145,27 +1133,16 @@ procedure TsWorksheet.CalcFormula(ACell: PCell);
|
||||
var
|
||||
parser: TsSpreadsheetParser;
|
||||
res: TsExpressionResult;
|
||||
formula: String;
|
||||
cell: PCell;
|
||||
p: Integer;
|
||||
link, txt: String;
|
||||
cell: PCell;
|
||||
begin
|
||||
ACell^.Flags := ACell^.Flags + [cfCalculating] - [cfCalculated];
|
||||
|
||||
parser := TsSpreadsheetParser.Create(self);
|
||||
try
|
||||
if ACell^.SharedFormulaBase = nil then
|
||||
begin
|
||||
formula := ACell^.FormulaValue;
|
||||
parser.ActiveCell := nil;
|
||||
end else
|
||||
begin
|
||||
formula := ACell^.SharedFormulaBase^.FormulaValue;
|
||||
parser.ActiveCell := ACell;
|
||||
end;
|
||||
|
||||
try
|
||||
parser.Expression := formula;
|
||||
parser.Expression := ACell^.FormulaValue;
|
||||
res := parser.Evaluate;
|
||||
except
|
||||
on E:ECalcEngine do
|
||||
@ -1248,9 +1225,7 @@ begin
|
||||
node := FCells.FindLowest;
|
||||
while Assigned(node) do begin
|
||||
cell := PCell(node.Data);
|
||||
if (cell^.ContentType <> cctError) and
|
||||
(HasFormula(cell) or HasFormula(cell^.SharedFormulaBase))
|
||||
then
|
||||
if (cell^.ContentType <> cctError) and HasFormula(cell) then
|
||||
CalcFormula(cell);
|
||||
node := FCells.FindSuccessor(node);
|
||||
end;
|
||||
@ -1496,7 +1471,6 @@ end;
|
||||
function TsWorksheet.ValidHyperlink(AValue: String; out AErrMsg: String): Boolean;
|
||||
var
|
||||
uri: TUri;
|
||||
mark: String;
|
||||
sheet: TsWorksheet;
|
||||
r, c: Cardinal;
|
||||
begin
|
||||
@ -1664,7 +1638,7 @@ begin
|
||||
if IsMergeBase(AFromCell) then
|
||||
begin
|
||||
FindMergedRange(AFromCell, row1, col1, row2, col2);
|
||||
MergeCells(toRow, toCol, toRow + row2 - row1, toCol + col2 - col1);
|
||||
MergeCells(toRow, toCol, toRow + LongInt(row2) - LongInt(row1), toCol + LongInt(col2) - LongInt(col1));
|
||||
end;
|
||||
|
||||
// Copy comment
|
||||
@ -1743,7 +1717,6 @@ end;
|
||||
procedure TsWorksheet.CopyFormula(AFromCell, AToCell: PCell);
|
||||
var
|
||||
rpnFormula: TsRPNFormula;
|
||||
lCell: TCell;
|
||||
begin
|
||||
if (AFromCell = nil) or (AToCell = nil) then
|
||||
exit;
|
||||
@ -1753,11 +1726,7 @@ begin
|
||||
else
|
||||
begin
|
||||
// Here we convert the formula to an rpn formula as seen from source...
|
||||
// (The mechanism needs the ActiveCell of the parser which is only
|
||||
// valid if the cell contains a shared formula)
|
||||
lCell := AToCell^;
|
||||
lCell.SharedFormulaBase := AFromCell;
|
||||
rpnFormula := BuildRPNFormula(@lCell);
|
||||
rpnFormula := BuildRPNFormula(AFromCell, AToCell);
|
||||
// ... and here we reconstruct the string formula as seen from destination cell.
|
||||
AToCell^.FormulaValue := ConvertRPNFormulaToStringFormula(rpnFormula);
|
||||
end;
|
||||
@ -1811,7 +1780,7 @@ end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Deletes a specified cell. If the cell belongs to a merged block its content
|
||||
and formatting is erased. Otherwise the cell is destroyed, its memory is
|
||||
and formatting is erased. Otherwise the cell is destroyed and its memory is
|
||||
released.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.DeleteCell(ACell: PCell);
|
||||
@ -1831,12 +1800,6 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Is base of shared formula block? Recreate individual formulas
|
||||
if ACell^.SharedFormulaBase = ACell then
|
||||
SplitSharedFormula(ACell);
|
||||
|
||||
// Belongs to shared formula block? --> nothing to do
|
||||
|
||||
// Destroy the cell, and remove it from the tree
|
||||
RemoveAndFreeCell(ACell^.Row, ACell^.Col);
|
||||
end;
|
||||
@ -2619,7 +2582,6 @@ end;
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
If a cell contains a formula (string formula or RPN formula) the formula
|
||||
is returned as a string in Excel syntax.
|
||||
If the cell belongs to a shared formula the adapted shared formula is returned.
|
||||
|
||||
@param ACell Pointer to the cell considered
|
||||
@param ALocalized If true, the formula is returned with decimal and list
|
||||
@ -2636,40 +2598,19 @@ begin
|
||||
if ACell = nil then
|
||||
exit;
|
||||
if HasFormula(ACell) then begin
|
||||
// case (1): Formula is localized and has to be converted to default syntax
|
||||
if ALocalized then
|
||||
begin
|
||||
// case (1): Formula is localized and has to be converted to default syntax // !!!! Is this comment correct?
|
||||
parser := TsSpreadsheetParser.Create(self);
|
||||
try
|
||||
if ACell^.SharedFormulaBase <> nil then begin
|
||||
// case (1a): shared formula
|
||||
parser.ActiveCell := ACell;
|
||||
parser.Expression := ACell^.SharedFormulaBase^.FormulaValue;
|
||||
end else begin
|
||||
// case (1b): normal formula
|
||||
parser.ActiveCell := nil;
|
||||
parser.Expression := ACell^.FormulaValue;
|
||||
end;
|
||||
parser.Expression := ACell^.FormulaValue;
|
||||
Result := parser.LocalizedExpression[Workbook.FormatSettings];
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
end
|
||||
else
|
||||
// case (2): Formula is in default syntax
|
||||
if ACell^.SharedFormulaBase <> nil then
|
||||
begin
|
||||
// case (2a): shared formula
|
||||
parser := TsSpreadsheetParser.Create(self);
|
||||
try
|
||||
parser.ActiveCell := ACell;
|
||||
parser.Expression := ACell^.SharedFormulaBase^.FormulaValue;
|
||||
Result := parser.Expression;
|
||||
finally
|
||||
parser.Free;
|
||||
end;
|
||||
end else
|
||||
// case (2b): normal formula
|
||||
// case (2): Formula is already in default syntax
|
||||
Result := ACell^.FormulaValue;
|
||||
end;
|
||||
end;
|
||||
@ -3121,7 +3062,6 @@ end;
|
||||
procedure TsWorksheet.UnmergeCells(ARow, ACol: Cardinal);
|
||||
var
|
||||
rng: PsCellRange;
|
||||
r, c: Cardinal;
|
||||
cell: PCell;
|
||||
begin
|
||||
rng := FMergedCells.FindRangeWithCell(ARow, ACol);
|
||||
@ -3155,23 +3095,6 @@ begin
|
||||
UnmergeCells(rng.Row1, rng.Col1);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Finds the upper left cell of a shared formula block to which the specified
|
||||
cell belongs. This is the "shared formula base".
|
||||
|
||||
@param ACell Cell under investigation
|
||||
@return A pointer to the cell in the upper left corner of the shared formula
|
||||
block to which ACell belongs. If ACell is not part of a shared formula
|
||||
block then the function returns NIL.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsWorksheet.FindSharedFormulaBase(ACell: PCell): PCell;
|
||||
begin
|
||||
if ACell = nil then
|
||||
Result := nil
|
||||
else
|
||||
Result := ACell^.SharedFormulaBase;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Determines the merged cell block to which a particular cell belongs
|
||||
|
||||
@ -3244,90 +3167,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
{ Shared formulas }
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Determines the cell block sharing the same formula which is used by a given cell
|
||||
|
||||
Note: the block may not be contiguous. The function returns the outer edges
|
||||
of the range.
|
||||
|
||||
@param ACell Pointer to the cell being investigated
|
||||
@param ARow1 (output) Top row index of the shared formula block
|
||||
@param ACol1 (outout) Left column index of the shared formula block
|
||||
@param ARow2 (output) Bottom row index of the shared formula block
|
||||
@param ACol2 (output) Right column index of the shared formula block
|
||||
|
||||
@return True if the cell belongs to a shared formula block, False if not or
|
||||
if the cell does not exist at all.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsWorksheet.FindSharedFormulaRange(ACell: PCell;
|
||||
out ARow1, ACol1, ARow2, ACol2: Cardinal): Boolean;
|
||||
var
|
||||
r, c: Cardinal;
|
||||
cell: PCell;
|
||||
base: PCell;
|
||||
lastCol, lastRow: Cardinal;
|
||||
begin
|
||||
base := FindSharedFormulaBase(ACell);
|
||||
if base = nil then begin
|
||||
Result := false;
|
||||
exit;
|
||||
end;
|
||||
// Assuming that the shared formula block is rectangular, we start at the base...
|
||||
ARow1 := base^.Row;
|
||||
ARow2 := ARow1;
|
||||
ACol1 := base^.Col;
|
||||
ACol2 := ACol1;
|
||||
lastCol := GetLastOccupiedColIndex;
|
||||
lastRow := GetLastOccupiedRowIndex;
|
||||
// ... and go along first COLUMN to find the end of the shared formula block, ...
|
||||
for c := ACol1+1 to lastCol do
|
||||
begin
|
||||
cell := FindCell(ARow1, c);
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = base) then
|
||||
ACol2 := c;
|
||||
end;
|
||||
// ... and go along first ROW to find the end of the shared formula block
|
||||
for r := ARow1 + 1 to lastRow do
|
||||
begin
|
||||
cell := FindCell(r, ACol1);
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = base) then
|
||||
ARow2 := r;
|
||||
end;
|
||||
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
A shared formula must contain at least two cells. If there is only a single
|
||||
cell then the shared formula is converted to a regular one.
|
||||
Is called before writing to stream.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.FixSharedFormulas;
|
||||
var
|
||||
r,c, r1,c1, r2,c2: Cardinal;
|
||||
cell: PCell;
|
||||
// firstRow, firstCol, lastRow, lastCol: Cardinal;
|
||||
begin
|
||||
for cell in Cells do
|
||||
if FindSharedFormulaRange(cell, r1, c1, r2, c2) and (r1 = r2) and (c1 = c2) then
|
||||
cell^.SharedFormulaBase := nil;
|
||||
{
|
||||
firstRow := GetFirstRowIndex;
|
||||
firstCol := GetFirstColIndex;
|
||||
lastRow := GetLastOccupiedRowIndex;
|
||||
lastCol := GetLastOccupiedColIndex;
|
||||
for r := firstRow to lastRow do
|
||||
for c := firstCol to lastCol do
|
||||
begin
|
||||
cell := FindCell(r, c);
|
||||
if FindSharedFormulaRange(cell, r1, c1, r2, c2) and (r1 = r2) and (c1 = c2) then
|
||||
cell^.SharedFormulaBase := nil;
|
||||
end;
|
||||
}
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Removes the comment from a cell and releases the memory occupied by the node.
|
||||
-------------------------------------------------------------------------------}
|
||||
@ -3745,72 +3584,6 @@ begin
|
||||
FLastRowIndex := GetLastRowIndex(true);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Splits a shared formula range to which the specified cell belongs into
|
||||
individual cells. Each cell gets the same formula as it had in the block.
|
||||
This is required because insertion and deletion of columns/rows make shared
|
||||
formulas very complicated.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.SplitSharedFormula(ACell: PCell);
|
||||
var
|
||||
r, c: Cardinal;
|
||||
baseRow, baseCol: Cardinal;
|
||||
lastRow, lastCol: Cardinal;
|
||||
cell: PCell;
|
||||
rpnFormula: TsRPNFormula;
|
||||
begin
|
||||
if (ACell = nil) or (ACell^.SharedFormulaBase = nil) then
|
||||
exit;
|
||||
lastRow := GetLastOccupiedRowIndex;
|
||||
lastCol := GetLastOccupiedColIndex;
|
||||
baseRow := ACell^.SharedFormulaBase^.Row;
|
||||
baseCol := ACell^.SharedFormulaBase^.Col;
|
||||
for r := baseRow to lastRow do
|
||||
for c := baseCol to lastCol do
|
||||
begin
|
||||
cell := FindCell(r, c);
|
||||
if (cell = nil) or (cell^.SharedFormulaBase = nil) then
|
||||
continue;
|
||||
if (cell^.SharedFormulaBase^.Row = baseRow) and
|
||||
(cell^.SharedFormulaBase^.Col = baseCol) then
|
||||
begin
|
||||
// This method converts the shared formula to an rpn formula as seen from cell...
|
||||
rpnFormula := BuildRPNFormula(cell);
|
||||
// ... and this reconstructs the string formula, again as seen from cell.
|
||||
cell^.FormulaValue := ConvertRPNFormulaToStringFormula(rpnFormula);
|
||||
// Remove the SharedFormulaBase information --> cell is isolated.
|
||||
cell^.SharedFormulaBase := nil;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Defines a cell range sharing the "same" formula. Note that relative cell
|
||||
references are updated for each cell in the range.
|
||||
|
||||
@param ARow Row of the cell
|
||||
@param ACol Column index of the cell
|
||||
@param ASharedFormulaBase Cell containing the shared formula
|
||||
|
||||
Note: An exception is raised if the cell already contains a formula (and is
|
||||
different from the ASharedFormulaBase cell).
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsWorksheet.UseSharedFormula(ARow, ACol: Cardinal;
|
||||
ASharedFormulaBase: PCell): PCell;
|
||||
begin
|
||||
if ASharedFormulaBase = nil then begin
|
||||
Result := nil;
|
||||
exit;
|
||||
end;
|
||||
Result := GetCell(ARow, ACol);
|
||||
Result.SharedFormulaBase := ASharedFormulaBase;
|
||||
if (Result^.FormulaValue <> '') and
|
||||
((ASharedFormulaBase.Row <> ARow) and (ASharedFormulaBase.Col <> ACol))
|
||||
then
|
||||
raise Exception.CreateFmt('[TsWorksheet.UseSharedFormula] Cell %s uses a shared formula, but contains an own formula.',
|
||||
[GetCellString(ARow, ACol)]);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes UTF-8 encoded text to a cell.
|
||||
|
||||
@ -3855,7 +3628,6 @@ begin
|
||||
begin
|
||||
if (Workbook.GetCellFormat(ACell^.FormatIndex).UsedFormattingFields = []) and
|
||||
(ACell^.Flags * [cfHyperlink, cfHasComment, cfMerged] = []) and
|
||||
(ACell^.SharedFormulaBase = nil) and
|
||||
(ACell^.FormulaValue = '')
|
||||
then
|
||||
begin
|
||||
@ -4052,8 +3824,6 @@ end;
|
||||
along a range of cells including empty cells.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.WriteBlank(ACell: PCell);
|
||||
var
|
||||
hyperlink: TsHyperlink;
|
||||
begin
|
||||
if ACell <> nil then begin
|
||||
if HasHyperlink(ACell) then
|
||||
@ -4818,57 +4588,6 @@ begin
|
||||
ChangedCell(ACell^.Row, ACell^.Col);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes a formula to a cell and shares it with other cells.
|
||||
|
||||
@param ARow1, ACol1 Row and column index of the top left corner of
|
||||
the range sharing the formula. The cell in this
|
||||
cell stores the formula.
|
||||
@param ARow2, ACol2 Row and column of the bottom right corner of the
|
||||
range sharing the formula.
|
||||
@param AFormula Formula in Excel notation
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.WriteSharedFormula(ARow1, ACol1, ARow2, ACol2: Cardinal;
|
||||
const AFormula: String);
|
||||
var
|
||||
cell: PCell;
|
||||
r, c: Cardinal;
|
||||
begin
|
||||
if (ARow1 > ARow2) or (ACol1 > ACol2) then
|
||||
raise Exception.Create('[TsWorksheet.WriteSharedFormula] Rows/cols not ordered correctly: ARow1 <= ARow2, ACol1 <= ACol2.');
|
||||
|
||||
if (ARow1 = ARow2) and (ACol1 = ACol2) then
|
||||
raise Exception.Create('[TsWorksheet.WriteSharedFormula] A shared formula range must contain at least two cells.');
|
||||
|
||||
// The cell at the top/left corner of the cell range is the "SharedFormulaBase".
|
||||
// It is the only cell which stores the formula.
|
||||
cell := WriteFormula(ARow1, ACol1, AFormula);
|
||||
for r := ARow1 to ARow2 do
|
||||
for c := ACol1 to ACol2 do
|
||||
UseSharedFormula(r, c, cell);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes a formula to a cell and shares it with other cells.
|
||||
|
||||
@param ACellRangeStr Range of cells which will use the shared formula.
|
||||
The range is given as a string in Excel notation,
|
||||
such as A1:B5, or A1
|
||||
@param AFormula Formula (in Excel notation) to be shared. The cell
|
||||
addresses are relative to the top/left cell of the
|
||||
range.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.WriteSharedFormula(ACellRange: String;
|
||||
const AFormula: String);
|
||||
var
|
||||
r1,r2, c1,c2: Cardinal;
|
||||
begin
|
||||
if ParseCellRangeString(ACellRange, r1, c1, r2, c2) then
|
||||
WriteSharedFormula(r1, c1, r2, c2, AFormula)
|
||||
else
|
||||
raise Exception.Create('[TsWorksheet.WriteSharedFormula] No valid cell range string.');
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Adds font specification to the formatting of a cell. Looks in the workbook's
|
||||
FontList and creates an new entry if the font is not used so far. Returns the
|
||||
@ -5699,20 +5418,12 @@ end;
|
||||
function TsWorksheet.CalcAutoRowHeight(ARow: Cardinal): Single;
|
||||
var
|
||||
cell: PCell;
|
||||
col: Integer;
|
||||
h0: Single;
|
||||
begin
|
||||
Result := 0;
|
||||
h0 := Workbook.GetDefaultFontSize;
|
||||
for cell in Cells.GetRowEnumerator(ARow) do
|
||||
Result := Max(Result, ReadCellFont(cell).Size / h0);
|
||||
{
|
||||
for col := GetFirstColIndex to GetLastColIndex do begin
|
||||
cell := FindCell(ARow, col);
|
||||
if cell <> nil then
|
||||
Result := Max(Result, ReadCellFont(cell).Size / h0);
|
||||
end;
|
||||
}
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
@ -5901,43 +5612,13 @@ procedure TsWorksheet.DeleteCol(ACol: Cardinal);
|
||||
var
|
||||
col: PCol;
|
||||
i: Integer;
|
||||
r, rr, cc: Cardinal;
|
||||
cell, basecell, nextcell: PCell;
|
||||
firstRow, lastCol, lastRow: Cardinal;
|
||||
r: Cardinal;
|
||||
cell: PCell;
|
||||
firstRow, lastRow: Cardinal;
|
||||
begin
|
||||
lastCol := GetLastColIndex;
|
||||
lastRow := GetLastOccupiedRowIndex;
|
||||
firstRow := GetFirstRowIndex;
|
||||
|
||||
// Loop along the column to be deleted and fix shared formulas
|
||||
for r := firstRow to lastRow do
|
||||
begin
|
||||
cell := FindCell(r, ACol);
|
||||
|
||||
// Fix shared formulas: if the deleted column contains the shared formula base
|
||||
// of a shared formula block then the shared formula has to be moved to the
|
||||
// next column
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = cell) then begin
|
||||
basecell := cell;
|
||||
nextcell := FindCell(r, ACol+1); // cell in next column and same row
|
||||
// Next cell in col at the right does not share this formula --> done with this formula
|
||||
if (nextcell = nil) or (nextcell^.SharedFormulaBase <> cell) then
|
||||
continue;
|
||||
// Write adapted formula to the cell below.
|
||||
WriteFormula(nextcell, basecell^.Formulavalue); //ReadFormulaAsString(nextcell));
|
||||
// Have all cells sharing the formula use the new formula base
|
||||
for rr := r to lastRow do
|
||||
for cc := ACol+1 to lastCol do
|
||||
begin
|
||||
cell := FindCell(rr, cc);
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = basecell) then
|
||||
cell^.SharedFormulaBase := nextcell
|
||||
else
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Fix merged cells
|
||||
FMergedCells.DeleteRowOrCol(ACol, false);
|
||||
|
||||
@ -5981,41 +5662,12 @@ procedure TsWorksheet.DeleteRow(ARow: Cardinal);
|
||||
var
|
||||
row: PRow;
|
||||
i: Integer;
|
||||
c, rr, cc: Cardinal;
|
||||
firstCol, lastCol, lastRow: Cardinal;
|
||||
cell, nextcell, basecell: PCell;
|
||||
c: Cardinal;
|
||||
firstCol, lastCol: Cardinal;
|
||||
cell: PCell;
|
||||
begin
|
||||
firstCol := GetFirstColIndex;
|
||||
lastCol := GetLastOccupiedColIndex;
|
||||
lastRow := GetLastOccupiedRowIndex;
|
||||
|
||||
// Loop along the row to be deleted and fix shared formulas
|
||||
for c := firstCol to lastCol do
|
||||
begin
|
||||
cell := FindCell(ARow, c);
|
||||
// Fix shared formulas: if the deleted row contains the shared formula base
|
||||
// of a shared formula block then the shared formula has to be moved to the
|
||||
// next row
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = cell) then begin
|
||||
basecell := cell;
|
||||
nextcell := FindCell(ARow+1, c); // cell in next row at same column
|
||||
// Next cell in row below does not share this formula --> done with this formula
|
||||
if (nextcell = nil) or (nextcell^.SharedFormulaBase <> cell) then
|
||||
continue;
|
||||
// Write adapted formula to the cell below.
|
||||
WriteFormula(nextcell, basecell^.FormulaValue); //ReadFormulaAsString(nextcell));
|
||||
// Have all cells sharing the formula use the new formula base
|
||||
for rr := ARow+1 to lastRow do
|
||||
for cc := c to lastCol do
|
||||
begin
|
||||
cell := FindCell(rr, cc);
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = basecell) then
|
||||
cell^.SharedFormulaBase := nextcell
|
||||
else
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Fix merged cells
|
||||
FMergedCells.DeleteRowOrCol(ARow, true);
|
||||
@ -6027,7 +5679,7 @@ begin
|
||||
FHyperlinks.DeleteRowOrCol(ARow, true);
|
||||
|
||||
// Delete cells
|
||||
for c := lastCol downto 0 do
|
||||
for c := lastCol downto firstCol do
|
||||
RemoveAndFreeCell(ARow, c);
|
||||
|
||||
// Update row index of cell records
|
||||
@ -6061,15 +5713,9 @@ procedure TsWorksheet.InsertCol(ACol: Cardinal);
|
||||
var
|
||||
col: PCol;
|
||||
i: Integer;
|
||||
r: Cardinal;
|
||||
cell: PCell;
|
||||
rng: PsCellRange;
|
||||
begin
|
||||
// Handling of shared formula references is too complicated for me...
|
||||
// Split them into isolated cell formulas
|
||||
for cell in FCells do
|
||||
SplitSharedFormula(cell);
|
||||
|
||||
// Update column index of comments
|
||||
FComments.InsertRowOrCol(ACol, false);
|
||||
|
||||
@ -6091,24 +5737,15 @@ begin
|
||||
|
||||
// Fix merged cells
|
||||
for rng in FMergedCells do
|
||||
// rng := PsCellRange(FMergedCells.GetFirst);
|
||||
// while rng <> nil do
|
||||
begin
|
||||
// The new column is at the LEFT of the merged block
|
||||
// --> Shift entire range to the right by 1 column
|
||||
if (ACol < rng^.Col1) then
|
||||
begin
|
||||
// The former first column is no longer marged --> un-tag its cells
|
||||
// The former first column is no longer merged --> un-tag its cells
|
||||
for cell in Cells.GetColEnumerator(rng^.Col1, rng^.Row1, rng^.Row2) do
|
||||
Exclude(cell^.Flags, cfMerged);
|
||||
{
|
||||
for r := rng^.Row1 to rng^.Row2 do
|
||||
begin
|
||||
cell := FindCell(r, rng^.Col1);
|
||||
if cell <> nil then
|
||||
Exclude(cell^.Flags, cfMerged);
|
||||
end;
|
||||
}
|
||||
|
||||
// Shift merged block to the right
|
||||
// Don't call "MergeCells" here - this would add a new merged block
|
||||
// because of the new merge base! --> infinite loop!
|
||||
@ -6117,21 +5754,11 @@ begin
|
||||
// The right column needs to be tagged
|
||||
for cell in Cells.GetColEnumerator(rng^.Col2, rng^.Row1, rng^.Row2) do
|
||||
Include(cell^.Flags, cfMerged);
|
||||
{
|
||||
for r := rng^.Row1 to rng^.Row2 do
|
||||
begin
|
||||
cell := FindCell(R, rng^.Col2);
|
||||
if cell <> nil then
|
||||
Include(cell^.Flags, cfMerged);
|
||||
end;
|
||||
}
|
||||
end else
|
||||
// The new column goes through this cell block --> Shift only the right
|
||||
// column of the range to the right by 1
|
||||
if (ACol >= rng^.Col1) and (ACol <= rng^.Col2) then
|
||||
MergeCells(rng^.Row1, rng^.Col1, rng^.Row2, rng^.Col2+1);
|
||||
// Continue with next merged block
|
||||
// rng := PsCellRange(FMergedCells.GetNext);
|
||||
end;
|
||||
|
||||
ChangedCell(0, ACol);
|
||||
@ -6187,15 +5814,9 @@ procedure TsWorksheet.InsertRow(ARow: Cardinal);
|
||||
var
|
||||
row: PRow;
|
||||
i: Integer;
|
||||
c: Cardinal;
|
||||
cell: PCell;
|
||||
rng: PsCellRange;
|
||||
begin
|
||||
// Handling of shared formula references is too complicated for me...
|
||||
// Splits them into isolated cell formulas
|
||||
for cell in FCells do
|
||||
SplitSharedFormula(cell);
|
||||
|
||||
// Update row index of cell comments
|
||||
FComments.InsertRowOrCol(ARow, true);
|
||||
|
||||
@ -6217,8 +5838,6 @@ begin
|
||||
|
||||
// Fix merged cells
|
||||
for rng in FMergedCells do
|
||||
// rng := PsCellRange(FMergedCells.GetFirst);
|
||||
// while rng <> nil do
|
||||
begin
|
||||
// The new row is ABOVE the merged block --> Shift entire range down by 1 row
|
||||
if (ARow < rng^.Row1) then
|
||||
@ -6226,14 +5845,7 @@ begin
|
||||
// The formerly first row is no longer merged --> un-tag its cells
|
||||
for cell in Cells.GetRowEnumerator(rng^.Row1, rng^.Col1, rng^.Col2) do
|
||||
Exclude(cell^.Flags, cfMerged);
|
||||
{
|
||||
for c := rng^.Col1 to rng^.Col2 do
|
||||
begin
|
||||
cell := FindCell(rng^.Row1, c);
|
||||
if cell <> nil then
|
||||
Exclude(cell^.Flags, cfMerged);
|
||||
end;
|
||||
}
|
||||
|
||||
// Shift merged block down
|
||||
// (Don't call "MergeCells" here - this would add a new merged block
|
||||
// because of the new merge base! --> infinite loop!)
|
||||
@ -6242,21 +5854,11 @@ begin
|
||||
// The last row needs to be tagged
|
||||
for cell in Cells.GetRowEnumerator(rng^.Row2, rng^.Col1, rng^.Col2) do
|
||||
Include(cell^.Flags, cfMerged);
|
||||
{
|
||||
for c := rng^.Col1 to rng^.Col2 do
|
||||
begin
|
||||
cell := FindCell(rng^.Row2, c);
|
||||
if cell <> nil then
|
||||
Include(cell^.Flags, cfMerged);
|
||||
end;
|
||||
}
|
||||
end else
|
||||
// The new row goes through this cell block --> Shift only the bottom row
|
||||
// of the range down by 1
|
||||
if (ARow >= rng^.Row1) and (ARow <= rng^.Row2) then
|
||||
MergeCells(rng^.Row1, rng^.Col1, rng^.Row2+1, rng^.Col2);
|
||||
// Continue with next block
|
||||
// rng := PsCellRange(FMergedCells.GetNext);
|
||||
end;
|
||||
|
||||
ChangedCell(ARow, 0);
|
||||
@ -6472,9 +6074,6 @@ begin
|
||||
// Updates fist/last column/row index
|
||||
UpdateCaches;
|
||||
|
||||
// Shared formulas must contain at least two cells
|
||||
FixSharedFormulas;
|
||||
|
||||
// Calculated formulas (if requested)
|
||||
if (boCalcBeforeSaving in FOptions) then
|
||||
for sheet in FWorksheets do
|
||||
@ -6717,22 +6316,6 @@ begin
|
||||
raise Exception.Create(rsUnsupportedWriteFormat);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Shared formulas must contain at least two cells. If it's a single cell, then
|
||||
the cell formula is converted to a standard one.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorkbook.FixSharedFormulas;
|
||||
var
|
||||
sheet: TsWorksheet;
|
||||
i: Integer;
|
||||
begin
|
||||
for i := 0 to GetWorksheetCount-1 do
|
||||
begin
|
||||
sheet := GetWorksheetByIndex(i);
|
||||
sheet.FixSharedFormulas
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Determines the maximum index of used columns and rows in all sheets of this
|
||||
workbook. Respects VirtualMode.
|
||||
|
@ -2692,12 +2692,14 @@ begin
|
||||
if ACell^.ContentType = cctError then
|
||||
AStrings.Add(Format('ErrorValue=%s', [GetEnumName(TypeInfo(TsErrorValue), ord(ACell^.ErrorValue))]));
|
||||
AStrings.Add(Format('FormulaValue=%s', [Worksheet.ReadFormulaAsString(ACell, true)]));
|
||||
{
|
||||
if ACell^.SharedFormulaBase = nil then
|
||||
AStrings.Add('SharedFormulaBase=')
|
||||
else
|
||||
AStrings.Add(Format('SharedFormulaBase=%s', [GetCellString(
|
||||
ACell^.SharedFormulaBase^.Row, ACell^.SharedFormulaBase^.Col)
|
||||
]));
|
||||
}
|
||||
if (cfHyperlink in ACell^.Flags) then
|
||||
begin
|
||||
hyperlink := Worksheet.FindHyperlink(ACell);
|
||||
|
@ -548,13 +548,11 @@ type
|
||||
{ Location of the cell }
|
||||
Row: Cardinal; // zero-based
|
||||
Col: Cardinal; // zero-based
|
||||
Worksheet: Pointer; // Must be cast to TsWorksheet when used
|
||||
Worksheet: Pointer; // Must be cast to TsWorksheet when used (avoids circular unit reference)
|
||||
{ Status flags }
|
||||
Flags: TsCellFlags;
|
||||
{ Index of format record in the workbook's FCellFormatList }
|
||||
FormatIndex: Integer;
|
||||
{ Special information }
|
||||
SharedFormulaBase: PCell; // Cell containing the shared formula
|
||||
{ Cell content }
|
||||
UTF8StringValue: String; // Strings cannot be part of a variant record
|
||||
FormulaValue: String;
|
||||
|
@ -33,13 +33,17 @@ type
|
||||
// Test reconstruction of formula strings
|
||||
procedure Test_Write_Read_FormulaStrings(AFormat: TsSpreadsheetFormat;
|
||||
UseRPNFormula: Boolean);
|
||||
{
|
||||
// Test reconstruction of shared formula strings
|
||||
procedure Test_Write_Read_SharedFormulaStrings(AFormat: TsSpreadsheetFormat);
|
||||
// Test calculation of formulas
|
||||
}
|
||||
procedure Test_Write_Read_CalcFormulas(AFormat: TsSpreadsheetformat;
|
||||
UseRPNFormula: Boolean);
|
||||
{
|
||||
// Test calculation of shared formulas
|
||||
procedure Test_Write_Read_CalcSharedFormulas(AFormat: TsSpreadsheetformat);
|
||||
}
|
||||
|
||||
published
|
||||
// Writes out formulas & reads them back.
|
||||
@ -54,6 +58,7 @@ type
|
||||
{ ODS Tests }
|
||||
procedure Test_Write_Read_FormulaStrings_ODS;
|
||||
|
||||
(*
|
||||
// Writes out shared formulas & reads them back.
|
||||
{ BIFF2 Tests }
|
||||
procedure Test_Write_Read_SharedFormulaStrings_BIFF2;
|
||||
@ -64,7 +69,7 @@ type
|
||||
{ OOXML Tests }
|
||||
procedure Test_Write_Read_SharedFormulaStrings_OOXML;
|
||||
{ ODS Tests }
|
||||
procedure Test_Write_Read_SharedFormulaStrings_ODS;
|
||||
procedure Test_Write_Read_SharedFormulaStrings_ODS; *)
|
||||
|
||||
// Writes out and calculates rpn formulas, read back
|
||||
{ BIFF2 Tests }
|
||||
@ -89,7 +94,7 @@ type
|
||||
procedure Test_Write_Read_CalcStringFormula_OOXML;
|
||||
{ ODS Tests }
|
||||
procedure Test_Write_Read_CalcStringFormula_ODS;
|
||||
|
||||
(*
|
||||
// Writes out and calculates shared formulas, read back
|
||||
{ BIFF2 Tests }
|
||||
procedure Test_Write_Read_CalcSharedFormula_BIFF2;
|
||||
@ -100,7 +105,7 @@ type
|
||||
{ OOXML Tests }
|
||||
procedure Test_Write_Read_CalcSharedFormula_OOXML;
|
||||
{ ODS Tests }
|
||||
procedure Test_Write_Read_CalcSharedFormula_ODS;
|
||||
procedure Test_Write_Read_CalcSharedFormula_ODS; *)
|
||||
|
||||
end;
|
||||
|
||||
@ -227,7 +232,7 @@ end;
|
||||
|
||||
|
||||
{ Test writing and reading (i.e. reconstruction) of shared formula strings }
|
||||
|
||||
(*
|
||||
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_SharedFormulaStrings(
|
||||
AFormat: TsSpreadsheetFormat);
|
||||
const
|
||||
@ -352,7 +357,7 @@ procedure TSpreadWriteReadFormulaTests.Test_Write_Read_SharedFormulaStrings_ODS;
|
||||
begin
|
||||
Test_Write_Read_SharedFormulaStrings(sfOpenDocument);
|
||||
end;
|
||||
|
||||
*)
|
||||
{ Test calculation of formulas }
|
||||
|
||||
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcFormulas(
|
||||
@ -550,6 +555,7 @@ end;
|
||||
//------------------------------------------------------------------------------
|
||||
// Calculation of shared formulas
|
||||
//------------------------------------------------------------------------------
|
||||
(*
|
||||
procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormulas(
|
||||
AFormat: TsSpreadsheetFormat);
|
||||
const
|
||||
@ -707,7 +713,7 @@ procedure TSpreadWriteReadFormulaTests.Test_Write_Read_CalcSharedFormula_ODS;
|
||||
begin
|
||||
Test_Write_Read_CalcSharedFormulas(sfOpenDocument);
|
||||
end;
|
||||
|
||||
*)
|
||||
|
||||
initialization
|
||||
// Register so these tests are included in a full run
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -128,10 +128,12 @@ type
|
||||
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal;
|
||||
const AFormula: TsRPNFormula; ACell: PCell); override;
|
||||
function WriteRPNFunc(AStream: TStream; AIdentifier: Word): Word; override;
|
||||
{
|
||||
procedure WriteRPNSharedFormulaLink(AStream: TStream; ACell: PCell;
|
||||
var RPNLength: Word); override;
|
||||
}
|
||||
procedure WriteRPNTokenArraySize(AStream: TStream; ASize: Word); override;
|
||||
procedure WriteSharedFormula(AStream: TStream; ACell: PCell); override;
|
||||
// procedure WriteSharedFormula(AStream: TStream; ACell: PCell); override;
|
||||
procedure WriteStringRecord(AStream: TStream; AString: String); override;
|
||||
procedure WriteWindow1(AStream: TStream); override;
|
||||
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
|
||||
@ -1670,10 +1672,11 @@ begin
|
||||
AStream.WriteByte(1);
|
||||
|
||||
{ Formula data (RPN token array) }
|
||||
{
|
||||
if ACell^.SharedFormulaBase <> nil then
|
||||
WriteRPNSharedFormulaLink(AStream, ACell, RPNLength)
|
||||
else
|
||||
WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength);
|
||||
else}
|
||||
WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength);
|
||||
|
||||
{ Finally write sizes after we know them }
|
||||
FinalPos := AStream.Position;
|
||||
@ -1683,7 +1686,7 @@ begin
|
||||
|
||||
{ Write following STRING record if formula result is a non-empty string }
|
||||
if (ACell^.ContentType = cctUTF8String) and (ACell^.UTF8StringValue <> '') then
|
||||
WriteStringRecord(AStream, ACell^.UTF8StringValue);
|
||||
WriteSTRINGRecord(AStream, ACell^.UTF8StringValue);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
@ -1696,7 +1699,7 @@ begin
|
||||
AStream.WriteByte(Lo(AIdentifier));
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
(*
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
This method is intended to write a link to the cell containing the shared
|
||||
formula used by the cell. But since BIFF2 does not support shared formulas
|
||||
@ -1721,7 +1724,7 @@ begin
|
||||
// Clean up
|
||||
SetLength(formula, 0);
|
||||
end;
|
||||
|
||||
*)
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes the size of the RPN token array. Called from WriteRPNFormula.
|
||||
Overrides xlscommon.
|
||||
@ -1731,7 +1734,7 @@ procedure TsSpreadBIFF2Writer.WriteRPNTokenArraySize(AStream: TStream;
|
||||
begin
|
||||
AStream.WriteByte(ASize);
|
||||
end;
|
||||
|
||||
(*
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Is intended to write the token array of a shared formula stored in ACell.
|
||||
But since BIFF2 does not support shared formulas this method must not do
|
||||
@ -1740,7 +1743,7 @@ end;
|
||||
procedure TsSpreadBIFF2Writer.WriteSharedFormula(AStream: TStream; ACell: PCell);
|
||||
begin
|
||||
Unused(AStream, ACell);
|
||||
end;
|
||||
end; *)
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes an Excel 2 STRING record which immediately follows a FORMULA record
|
||||
|
@ -355,8 +355,8 @@ const
|
||||
MASK_HLINK_ABSOLUTE = $00000002;
|
||||
MASK_HLINK_DESCRIPTION = $00000014;
|
||||
MASK_HLINK_TEXTMARK = $00000008;
|
||||
MASK_HLINK_TARGETFRAME = $00000080;
|
||||
MASK_HLINK_UNCPATH = $00000100;
|
||||
{%H-}MASK_HLINK_TARGETFRAME = $00000080;
|
||||
{%H-}MASK_HLINK_UNCPATH = $00000100;
|
||||
|
||||
SHAPEID_BASE = 1024;
|
||||
|
||||
@ -1446,7 +1446,7 @@ begin
|
||||
col2 := WordLEToN(AStream.ReadWord);
|
||||
|
||||
{ GUID of standard link }
|
||||
AStream.ReadBuffer(guid, SizeOf(guid));
|
||||
AStream.ReadBuffer(guid{%H-}, SizeOf(guid));
|
||||
|
||||
{ unknown DWord }
|
||||
AStream.ReadDWord;
|
||||
@ -2648,7 +2648,7 @@ procedure TsSpreadBIFF8Writer.WriteMergedCells(AStream: TStream;
|
||||
const
|
||||
MAX_PER_RECORD = 1026;
|
||||
var
|
||||
n0, n, i: Integer;
|
||||
n0, n: Integer;
|
||||
rng: PsCellRange;
|
||||
newRecord: Boolean;
|
||||
begin
|
||||
@ -2678,31 +2678,6 @@ begin
|
||||
n := Min(n0, MAX_PER_RECORD);
|
||||
end;
|
||||
end;
|
||||
(*
|
||||
while n0 > 0 do begin
|
||||
n := Min(n0, MAX_PER_RECORD);
|
||||
// at most 1026 merged ranges per BIFF record, the rest goes into a new record
|
||||
|
||||
{ BIFF record header }
|
||||
WriteBIFFHeader(AStream, INT_EXCEL_ID_MERGEDCELLS, 2 + n*8);
|
||||
|
||||
{ Number of cell ranges in this record }
|
||||
AStream.WriteWord(WordToLE(n));
|
||||
|
||||
{ Loop for writing the merged cell ranges }
|
||||
rng := PsCellRange(AWorksheet.MergedCells.GetFirst);
|
||||
while (n > 0) do begin
|
||||
AStream.WriteWord(WordToLE(rng^.Row1));
|
||||
AStream.WriteWord(WordToLE(rng^.Row2));
|
||||
AStream.WriteWord(WordToLE(rng^.Col1));
|
||||
AStream.WriteWord(WordToLE(rng^.Col2));
|
||||
dec(n);
|
||||
rng := PsCellRange(AWorksheet.MergedCells.GetNext);
|
||||
end;
|
||||
|
||||
dec(n0, MAX_PER_RECORD);
|
||||
end;
|
||||
*)
|
||||
end;
|
||||
|
||||
{@@-----------------------------------------------------------------------------
|
||||
|
@ -313,7 +313,8 @@ type
|
||||
out AFlags: TsRelFlags); virtual;
|
||||
function ReadRPNFunc(AStream: TStream): Word; virtual;
|
||||
procedure ReadRPNSharedFormulaBase(AStream: TStream; out ARow, ACol: Cardinal); virtual;
|
||||
function ReadRPNTokenArray(AStream: TStream; ACell: PCell): Boolean;
|
||||
function ReadRPNTokenArray(AStream: TStream; ACell: PCell;
|
||||
ASharedFormulaBase: PCell = nil): Boolean;
|
||||
function ReadRPNTokenArraySize(AStream: TStream): word; virtual;
|
||||
procedure ReadSharedFormula(AStream: TStream);
|
||||
|
||||
@ -404,8 +405,10 @@ type
|
||||
const AFormula: TsRPNFormula; ACell: PCell); virtual;
|
||||
function WriteRPNFunc(AStream: TStream; AIdentifier: Word): Word; virtual;
|
||||
procedure WriteRPNResult(AStream: TStream; ACell: PCell);
|
||||
{
|
||||
procedure WriteRPNSharedFormulaLink(AStream: TStream; ACell: PCell;
|
||||
var RPNLength: Word); virtual;
|
||||
}
|
||||
procedure WriteRPNTokenArray(AStream: TStream; ACell: PCell;
|
||||
const AFormula: TsRPNFormula; UseRelAddr: Boolean; var RPNLength: Word);
|
||||
procedure WriteRPNTokenArraySize(AStream: TStream; ASize: Word); virtual;
|
||||
@ -413,10 +416,12 @@ type
|
||||
// Writes out a SELECTION record
|
||||
procedure WriteSelection(AStream: TStream; ASheet: TsWorksheet; APane: Byte);
|
||||
procedure WriteSelections(AStream: TStream; ASheet: TsWorksheet);
|
||||
(*
|
||||
// Writes out a shared formula
|
||||
procedure WriteSharedFormula(AStream: TStream; ACell: PCell); virtual;
|
||||
procedure WriteSharedFormulaRange(AStream: TStream;
|
||||
AFirstRow, AFirstCol, ALastRow, ALastCol: Cardinal); virtual;
|
||||
*)
|
||||
procedure WriteSheetPR(AStream: TStream);
|
||||
procedure WriteStringRecord(AStream: TStream; AString: String); virtual;
|
||||
// Writes cell content received by workbook in OnNeedCellData event
|
||||
@ -1591,7 +1596,7 @@ end;
|
||||
rpn formula, converts it to a string formula and stores it in the cell.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsSpreadBIFFReader.ReadRPNTokenArray(AStream: TStream;
|
||||
ACell: PCell): Boolean;
|
||||
ACell: PCell; ASharedFormulaBase: PCell = nil): Boolean;
|
||||
var
|
||||
n: Word;
|
||||
p0: Int64;
|
||||
@ -1607,7 +1612,8 @@ var
|
||||
funcCode: Word;
|
||||
b: Byte;
|
||||
found: Boolean;
|
||||
formula: TsRPNformula;
|
||||
rpnFormula: TsRPNformula;
|
||||
strFormula: String;
|
||||
begin
|
||||
rpnItem := nil;
|
||||
n := ReadRPNTokenArraySize(AStream);
|
||||
@ -1652,16 +1658,16 @@ begin
|
||||
// For compatibility with other formats, convert offsets back to regular indexes.
|
||||
if (rfRelRow in flags)
|
||||
then r := LongInt(ACell^.Row) + dr
|
||||
else r := LongInt(ACell^.SharedFormulaBase^.Row) + dr;
|
||||
else r := LongInt(ASharedFormulaBase^.Row) + dr;
|
||||
if (rfRelRow2 in flags)
|
||||
then r2 := LongInt(ACell^.Row) + dr2
|
||||
else r2 := LongInt(ACell^.SharedFormulaBase^.Row) + dr2;
|
||||
else r2 := LongInt(ASharedFormulaBase^.Row) + dr2;
|
||||
if (rfRelCol in flags)
|
||||
then c := LongInt(ACell^.Col) + dc
|
||||
else c := LongInt(ACell^.SharedFormulaBase^.Col) + dc;
|
||||
else c := LongInt(ASharedFormulaBase^.Col) + dc;
|
||||
if (rfRelCol2 in flags)
|
||||
then c2 := LongInt(ACell^.Col) + dc2
|
||||
else c2 := LongInt(ACell^.SharedFormulaBase^.Col) + dc2;
|
||||
else c2 := LongInt(ASharedFormulaBase^.Col) + dc2;
|
||||
rpnItem := RPNCellRange(r, c, r2, c2, flags, rpnItem);
|
||||
end;
|
||||
INT_EXCEL_TOKEN_TMISSARG:
|
||||
@ -1710,12 +1716,9 @@ begin
|
||||
end;
|
||||
|
||||
INT_EXCEL_TOKEN_TEXP:
|
||||
// Indicates that cell belongs to a shared or array formula. We determine
|
||||
// the base cell of the shared formula and store it in the current cell.
|
||||
begin
|
||||
ReadRPNSharedFormulaBase(AStream, r, c);
|
||||
ACell^.SharedFormulaBase := FWorksheet.FindCell(r, c);
|
||||
end;
|
||||
// Indicates that cell belongs to a shared or array formula.
|
||||
// This information is not needed any more.
|
||||
ReadRPNSharedFormulaBase(AStream, r, c);
|
||||
|
||||
else
|
||||
found := false;
|
||||
@ -1734,11 +1737,16 @@ begin
|
||||
Result := false;
|
||||
end
|
||||
else begin
|
||||
formula := CreateRPNFormula(rpnItem, true); // true --> we have to flip the order of items!
|
||||
rpnFormula := CreateRPNFormula(rpnItem, true); // true --> we have to flip the order of items!
|
||||
strFormula := FWorksheet.ConvertRPNFormulaToStringFormula(rpnFormula);
|
||||
if strFormula <> '' then
|
||||
ACell^.FormulaValue := strFormula;
|
||||
{
|
||||
if (ACell^.SharedFormulaBase = nil) or (ACell = ACell^.SharedFormulaBase) then
|
||||
ACell^.FormulaValue := FWorksheet.ConvertRPNFormulaToStringFormula(formula)
|
||||
else
|
||||
ACell^.FormulaValue := '';
|
||||
}
|
||||
Result := true;
|
||||
end;
|
||||
end;
|
||||
@ -1760,7 +1768,7 @@ end;
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsSpreadBIFFReader.ReadSharedFormula(AStream: TStream);
|
||||
var
|
||||
r1, {%H-}r2, c1, {%H-}c2: Cardinal;
|
||||
r, r1, r2, c, c1, c2: Cardinal;
|
||||
cell: PCell;
|
||||
begin
|
||||
// Cell range in which the formula is valid
|
||||
@ -1769,12 +1777,12 @@ begin
|
||||
c1 := AStream.ReadByte; // 8 bit, even for BIFF8
|
||||
c2 := AStream.ReadByte;
|
||||
|
||||
{ Create cell }
|
||||
{ Create cell - this is the "base" of the shared formula }
|
||||
if FIsVirtualMode then begin // "Virtual" cell
|
||||
InitCell(r1, c1, FVirtualCell);
|
||||
cell := @FVirtualCell;
|
||||
end else
|
||||
cell := FWorksheet.GetCell(r1, c1); // "Real" cell
|
||||
cell := FWorksheet.GetCell(r1, c1); // "Real" cell
|
||||
|
||||
// Unused
|
||||
AStream.ReadByte;
|
||||
@ -1783,7 +1791,12 @@ begin
|
||||
AStream.ReadByte;
|
||||
|
||||
// RPN formula tokens
|
||||
ReadRPNTokenArray(AStream, cell);
|
||||
ReadRPNTokenArray(AStream, cell, cell); //base);
|
||||
|
||||
// Copy shared formula to individual cells in the specified range
|
||||
for r := r1 to r2 do
|
||||
for c := c1 to c2 do
|
||||
FWorksheet.CopyFormula(cell, r, c);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
@ -2534,8 +2547,12 @@ begin
|
||||
if (ARow >= FLimitations.MaxRowCount) or (ACol >= FLimitations.MaxColCount) then
|
||||
exit;
|
||||
|
||||
if Length(AFormula) = 0 then
|
||||
exit;
|
||||
{
|
||||
if not ((Length(AFormula) > 0) or (ACell^.SharedFormulaBase <> nil)) then
|
||||
exit;
|
||||
}
|
||||
|
||||
{ BIFF Record header }
|
||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMULA));
|
||||
@ -2560,18 +2577,19 @@ begin
|
||||
AStream.WriteDWord(0);
|
||||
|
||||
{ Formula data (RPN token array) }
|
||||
{
|
||||
if ACell^.SharedFormulaBase <> nil then
|
||||
WriteRPNSharedFormulaLink(AStream, ACell, RPNLength)
|
||||
else
|
||||
WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength);
|
||||
}
|
||||
WriteRPNTokenArray(AStream, ACell, AFormula, false, RPNLength);
|
||||
|
||||
{ Write sizes in the end, after we known them }
|
||||
FinalPos := AStream.Position;
|
||||
AStream.Position := RecordSizePos;
|
||||
AStream.WriteWord(WordToLE(FinalPos - StartPos));
|
||||
// AStream.WriteWord(WordToLE(22 + RPNLength));
|
||||
AStream.Position := FinalPos;
|
||||
|
||||
(*
|
||||
{ If the cell is the first cell of a range with a shared formula write the
|
||||
shared formula RECORD here. The shared formula RECORD must follow the
|
||||
first FORMULA record referring to the shared formula}
|
||||
@ -2580,10 +2598,11 @@ begin
|
||||
(ACol = ACell^.SharedFormulaBase^.Col)
|
||||
then
|
||||
WriteSharedFormula(AStream, ACell^.SharedFormulaBase);
|
||||
*)
|
||||
|
||||
{ Write following STRING record if formula result is a non-empty string. }
|
||||
if (ACell^.ContentType = cctUTF8String) and (ACell^.UTF8StringValue <> '') then
|
||||
WriteStringRecord(AStream, ACell^.UTF8StringValue);
|
||||
WriteSTRINGRecord(AStream, ACell^.UTF8StringValue);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
@ -2642,7 +2661,7 @@ begin
|
||||
{ Write result of the formula, encoded above }
|
||||
AStream.WriteBuffer(Data, 8);
|
||||
end;
|
||||
|
||||
(*
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Is called from WriteRPNFormula in the case that the cell uses a shared
|
||||
formula and writes the token "array" pointing to the shared formula base.
|
||||
@ -2669,6 +2688,7 @@ begin
|
||||
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||
RPNLength := SizeOf(rec);
|
||||
end;
|
||||
*)
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes the token array of the given RPN formula and returns its size
|
||||
@ -3014,7 +3034,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
(*
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes the token array of a shared formula stored in ACell.
|
||||
Note: Relative cell addresses of a shared formula are defined by
|
||||
@ -3083,7 +3103,7 @@ begin
|
||||
AStream.WriteByte(AFirstCol);
|
||||
// Index to last rcolumn
|
||||
AStream.WriteByte(ALastCol);
|
||||
end;
|
||||
end; *)
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes a SHEETPR Record.
|
||||
|
@ -67,7 +67,7 @@ type
|
||||
FBorderList: TFPList;
|
||||
FHyperlinkList: TFPList;
|
||||
FThemeColors: array of TsColorValue;
|
||||
FSharedFormulas: TStringList;
|
||||
// FSharedFormulas: TStringList;
|
||||
FWrittenByFPS: Boolean;
|
||||
procedure ApplyCellFormatting(ACell: PCell; XfIndex: Integer);
|
||||
procedure ApplyHyperlinks(AWorksheet: TsWorksheet);
|
||||
@ -467,7 +467,7 @@ begin
|
||||
// Set up the default palette in order to have the default color names correct.
|
||||
Workbook.UseDefaultPalette;
|
||||
|
||||
FSharedFormulas := TStringList.Create;
|
||||
// FSharedFormulas := TStringList.Create;
|
||||
FSharedStrings := TStringList.Create;
|
||||
FFillList := TFPList.Create;
|
||||
FBorderList := TFPList.Create;
|
||||
@ -493,7 +493,7 @@ begin
|
||||
FHyperlinkList.Free;
|
||||
|
||||
FSharedStrings.Free;
|
||||
FSharedFormulas.Free;
|
||||
// FSharedFormulas.Free;
|
||||
// FCellFormatList is destroyed by ancestor
|
||||
|
||||
inherited Destroy;
|
||||
@ -677,6 +677,8 @@ var
|
||||
sstIndex: Integer;
|
||||
number: Double;
|
||||
fmt: TsCellFormat;
|
||||
rng: TsCellRange;
|
||||
r,c: Cardinal;
|
||||
begin
|
||||
if ANode = nil then
|
||||
exit;
|
||||
@ -720,14 +722,21 @@ begin
|
||||
begin
|
||||
// Shared formula
|
||||
s := GetAttrValue(datanode, 'ref');
|
||||
if (s <> '') then // This is the shared formula base
|
||||
if (s <> '') then // This is the shared formula range
|
||||
begin
|
||||
// Split shared formula into single-cell formulas
|
||||
ParseCellRangeString(s, rng);
|
||||
for r := rng.Row1 to rng.Row2 do
|
||||
for c := rng.Col1 to rng.Col2 do
|
||||
FWorksheet.CopyFormula(cell, r, c);
|
||||
(*
|
||||
s := GetAttrValue(datanode, 'si');
|
||||
if s <> '' then
|
||||
FSharedFormulas.AddObject(addr, {%H-}Pointer(PtrInt(StrToInt(s))));
|
||||
FWorksheet.WriteFormula(cell, formulaStr);
|
||||
cell^.SharedFormulaBase := cell;
|
||||
//AWorksheet.WriteSharedFormula(s, formulaStr);
|
||||
AWorksheet.WriteSharedFormula(s, formulaStr);
|
||||
|
||||
end else
|
||||
begin
|
||||
s := GetAttrValue(datanode, 'si');
|
||||
@ -736,6 +745,7 @@ begin
|
||||
s := FSharedFormulas[FSharedFormulas.IndexOfObject({%H-}Pointer(PtrInt(StrToInt(s))))];
|
||||
cell^.SharedFormulaBase := FWorksheet.FindCell(s);
|
||||
end;
|
||||
*)
|
||||
end;
|
||||
end
|
||||
else
|
||||
@ -3279,9 +3289,6 @@ procedure TsSpreadOOXMLWriter.WriteFormula(AStream: TStream;
|
||||
var
|
||||
cellPosText: String;
|
||||
lStyleIndex: Integer;
|
||||
r, r1, r2: Cardinal;
|
||||
c, c1, c2: Cardinal;
|
||||
cell: PCell;
|
||||
t, v: String;
|
||||
begin
|
||||
cellPosText := TsWorksheet.CellPosToText(ARow, ACol);
|
||||
@ -3323,62 +3330,7 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Cell uses a shared formula
|
||||
if Assigned(ACell^.SharedFormulaBase) then begin
|
||||
// Cell is base of the shared formula, i.e. contains the shared formula
|
||||
if (ACell = ACell^.SharedFormulaBase) then
|
||||
begin
|
||||
// Find range of cells using this shared formula
|
||||
// The base of the shared formula is the left/top edge of the range
|
||||
r1 := ACell^.Row;
|
||||
r2 := r1;
|
||||
r := r1 + 1;
|
||||
while r <= FWorksheet.GetLastRowIndex do
|
||||
begin
|
||||
cell := FWorksheet.FindCell(r, ACell^.Col);
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = ACell^.SharedFormulaBase) then
|
||||
r2 := r
|
||||
else
|
||||
break;
|
||||
inc(r);
|
||||
end;
|
||||
c1 := ACell^.Col;
|
||||
c2 := c1;
|
||||
c := c1 + 1;
|
||||
while c <= FWorksheet.GetLastColIndex do
|
||||
begin
|
||||
cell := FWorksheet.FindCell(ACell^.Row, c);
|
||||
if (cell <> nil) and (cell^.SharedFormulaBase = ACell^.SharedFormulaBase) then
|
||||
c2 := c
|
||||
else
|
||||
break;
|
||||
inc(c);
|
||||
end;
|
||||
AppendToStream(AStream, Format(
|
||||
'<c r="%s" s="%d"%s>' +
|
||||
'<f t="shared" ref="%s" si="%d">%s</f>' +
|
||||
'%s' +
|
||||
'</c>', [
|
||||
CellPosText, lStyleIndex, t,
|
||||
GetCellRangeString(ACell^.Row, ACell^.Col, r2, c2),
|
||||
{%H-}PtrInt(ACell), // Use the cell pointer as ID of the shared formula
|
||||
PrepareFormula(ACell^.FormulaValue),
|
||||
v
|
||||
]));
|
||||
end else
|
||||
// Cell uses the shared formula
|
||||
AppendToStream(AStream, Format(
|
||||
'<c r="%s" s="%d"%s>' +
|
||||
'<f t="shared" si="%d" />' +
|
||||
'%s' +
|
||||
'</c>', [
|
||||
CellPosText, lStyleIndex, t,
|
||||
{%H-}PtrInt(ACell^.SharedFormulaBase), // ID of the shared formula
|
||||
v
|
||||
]));
|
||||
end else begin
|
||||
// "normal" formula
|
||||
AppendToStream(AStream, Format(
|
||||
AppendToStream(AStream, Format(
|
||||
'<c r="%s" s="%d"%s>' +
|
||||
'<f>%s</f>' +
|
||||
'%s' +
|
||||
@ -3386,8 +3338,7 @@ begin
|
||||
CellPosText, lStyleIndex, t,
|
||||
PrepareFormula(ACell^.FormulaValue),
|
||||
v
|
||||
]));
|
||||
end;
|
||||
]));
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user