You've already forked lazarus-ccr
fpspreadsheet: Replace prev commit by better fix for formulas with return a blank cell being lost.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5752 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@@ -1231,7 +1231,9 @@ var
|
||||
p: Integer;
|
||||
link, txt: String;
|
||||
cell: PCell;
|
||||
formula: String;
|
||||
begin
|
||||
formula := ACell^.FormulaValue;
|
||||
ACell^.Flags := ACell^.Flags + [cfCalculating] - [cfCalculated];
|
||||
|
||||
parser := TsSpreadsheetParser.Create(self);
|
||||
@@ -1283,6 +1285,8 @@ begin
|
||||
parser.Free;
|
||||
end;
|
||||
|
||||
// Restore the formula. Could have been erased by WriteBlank or WriteText('')
|
||||
ACell^.FormulaValue := formula;
|
||||
ACell^.Flags := ACell^.Flags + [cfCalculated] - [cfCalculating];
|
||||
end;
|
||||
|
||||
@@ -1315,7 +1319,6 @@ begin
|
||||
for cell in FCells do
|
||||
if HasFormula(cell) and (cell^.ContentType <> cctError) then
|
||||
CalcFormula(cell);
|
||||
|
||||
finally
|
||||
dec(FWorkbook.FCalculationLock);
|
||||
end;
|
||||
@@ -4823,14 +4826,16 @@ end;
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes an empty cell
|
||||
|
||||
@param ACel Pointer to the cell
|
||||
@param ACel Pointer to the cell
|
||||
Note: Empty cells are useful when, for example, a border line extends
|
||||
along a range of cells including empty cells.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.WriteBlank(ACell: PCell);
|
||||
begin
|
||||
if ACell <> nil then begin
|
||||
//ACell^.FormulaValue := '';
|
||||
ACell^.FormulaValue := '';
|
||||
// NOTE: Erase the formula because if it would return a non-blank result
|
||||
// this would be very confusing!
|
||||
if HasHyperlink(ACell) then
|
||||
WriteText(ACell, '') // '' will be replaced by the hyperlink target.
|
||||
else
|
||||
|
@@ -65,6 +65,7 @@ type
|
||||
procedure ReadNumber(AStream: TStream); override;
|
||||
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); override;
|
||||
procedure ReadRowInfo(AStream: TStream); override;
|
||||
function ReadRPNAttr(AStream: TStream; AIdentifier: Byte): Boolean; override;
|
||||
function ReadRPNFunc(AStream: TStream): Word; override;
|
||||
procedure ReadRPNSharedFormulaBase(AStream: TStream; out ARow, ACol: Cardinal); override;
|
||||
function ReadRPNTokenArraySize(AStream: TStream): Word; override;
|
||||
@@ -931,6 +932,16 @@ begin
|
||||
lRow^.FormatIndex := XFToFormatIndex(xf);
|
||||
end;
|
||||
|
||||
function TsSpreadBIFF2Reader.ReadRPNAttr(AStream: TStream; AIdentifier: Byte): Boolean;
|
||||
begin
|
||||
Result := false;
|
||||
case AIdentifier of
|
||||
$01: AStream.ReadByte; // tAttrVolatile
|
||||
else exit; // others not supported by fpspreadsheet --> Result = false
|
||||
end;
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads the identifier for an RPN function with fixed argument count from the
|
||||
stream.
|
||||
|
@@ -452,6 +452,7 @@ type
|
||||
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); virtual;
|
||||
// Read row info
|
||||
procedure ReadRowInfo(AStream: TStream); virtual;
|
||||
function ReadRPNAttr(AStream: TStream; AIdentifier: Byte): boolean; virtual;
|
||||
// Read the array of RPN tokens of a formula
|
||||
procedure ReadRPNCellAddress(AStream: TStream; out ARow, ACol: Cardinal;
|
||||
out AFlags: TsRelFlags); virtual;
|
||||
@@ -2154,6 +2155,24 @@ begin
|
||||
FWorksheet.WriteRowInfo(rowrec.RowIndex, lRow);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads the special attribute of an RPN formula element.
|
||||
Attributes are ignored by fpspreadsheet.
|
||||
Structure is value for BIFF3 - BIFF8. Must be overridden for BIFF2.
|
||||
Returns false if the structure is too complex for fps.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsSpreadBIFFReader.ReadRPNAttr(AStream: TStream; AIdentifier: Byte): Boolean;
|
||||
var
|
||||
w: Word;
|
||||
begin
|
||||
Result := false;
|
||||
case AIdentifier of
|
||||
$01: AStream.ReadWord; // tAttrVolatile token
|
||||
else exit; // others not supported by fps --> Result = false
|
||||
end;
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads the cell address used in an RPN formula element.
|
||||
Evaluates the corresponding bits to distinguish between absolute and
|
||||
@@ -2511,6 +2530,11 @@ begin
|
||||
while (AStream.Position < p0 + ARPNTokenArraySize) and supported do begin
|
||||
token := AStream.ReadByte;
|
||||
case token of
|
||||
INT_EXCEL_TOKEN_TATTR:
|
||||
begin
|
||||
b := AStream.ReadByte;
|
||||
supported := ReadRPNAttr(AStream, b);
|
||||
end;
|
||||
INT_EXCEL_TOKEN_TREFV:
|
||||
begin
|
||||
ReadRPNCellAddress(AStream, r, c, flags);
|
||||
|
@@ -34,12 +34,21 @@ const
|
||||
INT_EXCEL_TOKEN_TPAREN = $15; // Operator in parenthesis
|
||||
|
||||
{ Constant Operand Tokens, 3.8}
|
||||
INT_EXCEL_TOKEN_TMISSARG = $16; //missing operand
|
||||
INT_EXCEL_TOKEN_TSTR = $17; //string
|
||||
INT_EXCEL_TOKEN_TERR = $1C; //error value
|
||||
INT_EXCEL_TOKEN_TBOOL = $1D; //boolean
|
||||
INT_EXCEL_TOKEN_TINT = $1E; //(unsigned) integer
|
||||
INT_EXCEL_TOKEN_TNUM = $1F; //floating-point
|
||||
INT_EXCEL_TOKEN_TMISSARG = $16; // missing operand
|
||||
INT_EXCEL_TOKEN_TSTR = $17; // string
|
||||
INT_EXCEL_TOKEN_TERR = $1C; // error value
|
||||
INT_EXCEL_TOKEN_TBOOL = $1D; // boolean
|
||||
INT_EXCEL_TOKEN_TINT = $1E; // (unsigned) integer
|
||||
INT_EXCEL_TOKEN_TNUM = $1F; // floating-point
|
||||
|
||||
{ Control Tokens, Special Tokens, 3.10 }
|
||||
// 01H tExp Matrix formula or shared formula
|
||||
// 02H tTbl Multiple operation table
|
||||
// 15H tParen Parentheses
|
||||
// 18H tNlr Natural language reference (BIFF8)
|
||||
INT_EXCEL_TOKEN_TATTR = $19; // tAttr Special attribute
|
||||
// 1AH tSheet Start of external sheet reference (BIFF2-BIFF4)
|
||||
// 1BH tEndSheet End of external sheet reference (BIFF2-BIFF4)
|
||||
|
||||
{ Operand Tokens }
|
||||
// _R: reference; _V: value; _A: array
|
||||
@@ -259,14 +268,6 @@ const
|
||||
|
||||
INT_EXCEL_SHEET_FUNC_HYPERLINK = 359; // BIFF8 only
|
||||
|
||||
{ Control Tokens, Special Tokens }
|
||||
// 01H tExp Matrix formula or shared formula
|
||||
// 02H tTbl Multiple operation table
|
||||
// 15H tParen Parentheses
|
||||
// 18H tNlr Natural language reference (BIFF8)
|
||||
INT_EXCEL_TOKEN_TATTR = $19; // tAttr Special attribute
|
||||
// 1AH tSheet Start of external sheet reference (BIFF2-BIFF4)
|
||||
// 1BH tEndSheet End of external sheet reference (BIFF2-BIFF4)
|
||||
|
||||
|
||||
implementation
|
||||
|
@@ -308,6 +308,13 @@ type
|
||||
Tooltip: String;
|
||||
end;
|
||||
|
||||
TSharedFormulaData = class
|
||||
Worksheet: TsWorksheet;
|
||||
Row: Integer;
|
||||
Col: Integer;
|
||||
Formula: String;
|
||||
end;
|
||||
|
||||
const
|
||||
PATTERN_TYPES: array [TsFillStyle] of string = (
|
||||
'none', // fsNoFill
|
||||
@@ -327,7 +334,7 @@ const
|
||||
'lightDown', // fsThinStripeDiagDown
|
||||
'darkTrellis', // fsHatchDiag
|
||||
'lightTrellis', // fsHatchThinDiag
|
||||
'darkTellis', // fsHatchTickDiag
|
||||
'darkTellis', // fsHatchThickDiag
|
||||
'lightGrid' // fsHatchThinHor
|
||||
);
|
||||
|
||||
@@ -359,19 +366,25 @@ destructor TsSpreadOOXMLReader.Destroy;
|
||||
var
|
||||
j: Integer;
|
||||
begin
|
||||
for j := FFillList.Count-1 downto 0 do TObject(FFillList[j]).Free;
|
||||
for j := FFillList.Count-1 downto 0 do
|
||||
TObject(FFillList[j]).Free;
|
||||
FFillList.Free;
|
||||
|
||||
for j := FBorderList.Count-1 downto 0 do TObject(FBorderList[j]).Free;
|
||||
for j := FBorderList.Count-1 downto 0 do
|
||||
TObject(FBorderList[j]).Free;
|
||||
FBorderList.Free;
|
||||
|
||||
for j := FHyperlinkList.Count-1 downto 0 do TObject(FHyperlinkList[j]).Free;
|
||||
for j := FHyperlinkList.Count-1 downto 0 do
|
||||
TObject(FHyperlinkList[j]).Free;
|
||||
FHyperlinkList.Free;
|
||||
|
||||
for j := FSharedStrings.Count-1 downto 0 do
|
||||
if FSharedstrings.Objects[j] <> nil then FSharedStrings.Objects[j].Free;
|
||||
FSharedStrings.Objects[j].Free;
|
||||
FSharedStrings.Free;
|
||||
FSharedFormulaBaseList.Free; // Don't free items, they are worksheet cells
|
||||
|
||||
for j := FSharedFormulaBaseList.Count-1 downto 0 do
|
||||
TObject(FSharedFormulaBaseList[j]).Free;
|
||||
FSharedFormulaBaseList.Free;
|
||||
|
||||
// FCellFormatList, FNumFormatList and FFontList are destroyed by ancestor
|
||||
|
||||
@@ -582,7 +595,9 @@ procedure TsSpreadOOXMLReader.ReadCell(ANode: TDOMNode; AWorksheet: TsWorksheet)
|
||||
var
|
||||
addr, s: String;
|
||||
rowIndex, colIndex: Cardinal;
|
||||
cell, sharedformulabase: PCell;
|
||||
cell: PCell;
|
||||
lCell: TCell;
|
||||
sharedFormulabase: TSharedFormulaData;
|
||||
datanode, tnode: TDOMNode;
|
||||
dataStr: String;
|
||||
formulaStr: String;
|
||||
@@ -655,18 +670,28 @@ begin
|
||||
s := GetAttrValue(datanode, 'ref');
|
||||
if (s <> '') then // This defines the shared formula range
|
||||
begin
|
||||
AWorksheet.WriteFormula(cell, FormulaStr);
|
||||
AWorksheet.WriteFormula(cell, formulaStr);
|
||||
// We store the shared formula base in the SharedFormulaBaseList.
|
||||
// The list index is identical with the 'si' attribute of the node.
|
||||
FSharedFormulaBaseList.Add(cell);
|
||||
sharedformulabase := TSharedFormulaData.Create;
|
||||
sharedformulabase.Worksheet := FWorksheet;
|
||||
sharedformulabase.Row := rowindex;
|
||||
sharedformulabase.Col := colindex;
|
||||
sharedformulabase.Formula := formulaStr;
|
||||
FSharedFormulaBaseList.Add(sharedformulabase);
|
||||
end else
|
||||
begin
|
||||
// Get index into the SharedFormulaBaseList
|
||||
// Get index into the SharedFormulaBaseList...
|
||||
s := GetAttrValue(datanode, 'si');
|
||||
if s <> '' then
|
||||
begin
|
||||
sharedformulabase := PCell(FSharedFormulaBaseList[StrToInt(s)]);
|
||||
FWorksheet.CopyFormula(sharedformulabase, rowindex, colindex);
|
||||
sharedformulabase := TSharedFormulaData(FSharedFormulaBaseList[StrToInt(s)]);
|
||||
// ... and copy shared formula to destination cell
|
||||
InitCell(sharedformulabase.Row, sharedformulabase.Col, lCell);
|
||||
lCell.Formulavalue := sharedformulabase.Formula;
|
||||
lCell.Worksheet := sharedformulabase.Worksheet;
|
||||
FWorksheet.CopyFormula(@lCell, cell);
|
||||
cell^.ContentType := cctFormula;
|
||||
end;
|
||||
end;
|
||||
end
|
||||
@@ -681,8 +706,9 @@ begin
|
||||
s := GetAttrValue(ANode, 't'); // "t" = data type
|
||||
if (s = '') and (dataStr = '') then
|
||||
begin
|
||||
formulaStr := cell^.FormulaValue;
|
||||
AWorksheet.WriteBlank(cell); // this erases the formula!!!
|
||||
if formulaStr <> '' then cell^.FormulaValue := formulaStr;
|
||||
cell^.FormulaValue := formulaStr;
|
||||
end else
|
||||
if (s = '') or (s = 'n') then begin
|
||||
// Number or date/time, depending on format
|
||||
@@ -713,10 +739,12 @@ begin
|
||||
ms.ReadBuffer(cell^.RichTextParams[0], n*SizeOf(TsRichTextParam));
|
||||
end;
|
||||
end else
|
||||
if (s = 'str') or (s = 'inlineStr') then
|
||||
if (s = 'str') or (s = 'inlineStr') then begin
|
||||
// literal string
|
||||
AWorksheet.WriteText(cell, datastr)
|
||||
else
|
||||
formulaStr := cell^.FormulaValue;
|
||||
AWorksheet.WriteText(cell, datastr);
|
||||
cell^.FormulaValue := formulaStr;
|
||||
end else
|
||||
if s = 'b' then
|
||||
// boolean
|
||||
AWorksheet.WriteBoolValue(cell, dataStr='1')
|
||||
|
Reference in New Issue
Block a user