fpspreadsheet: Fix shared formulas incorrectly read from xlsx files. Fix formulas being lost when reading xlsx and ods files where formulas had not been calculated at saving.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4058 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-03-20 23:24:12 +00:00
parent 34ec877414
commit beca637d7c
4 changed files with 38 additions and 52 deletions

View File

@ -1275,6 +1275,7 @@ begin
ApplyStyleToCell(cell, stylename);
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
formula := '';
if (boReadFormulas in FWorkbook.Options) then
begin
// Read formula, trim it, ...
@ -1352,6 +1353,7 @@ begin
FWorksheet.WriteBoolValue(cell, boolValue);
end else
// (e) Text
if (valueStr <> '') then
FWorksheet.WriteUTF8Text(cell, valueStr);
if FIsVirtualMode then
@ -4219,11 +4221,6 @@ begin
hyperlink := FWorksheet.FindHyperlink(ACell);
SplitHyperlink(hyperlink^.Target, target, bookmark);
{
if (target = '') and (bookmark <> '') then
target := '#' + bookmark
else
}
if (target <> '') and (pos('file:', target) = 0) then
begin
u := ParseURI(target);
@ -4237,33 +4234,11 @@ begin
if (bookmark <> '') then
target := target + '#' + bookmark;
{
u := ParseURI(hyperlink^.Target);
if u.Protocol = '' then // relative file name, or internal link
begin
if target <> '' then target := '../' + target;
if bookmark <> '' then target := target + '#' + bookmark;
end else
target := hyperlink^.Target;
}
//ValidXMLText(target);
{
target := hyperlink^.Target;
if target[1] <> '#' then
begin
u := ParseURI(target);
if u.Protocol = '' then begin
//UriToFileName(hyperlink^.Target, target);
target := 'file:///' + ExpandFileName(target);
ValidXMLText(target);
// if not IsAbsoluteURI(target) then target := '..\' + target;
end;
end;
}
textp := Format(
'<text:p>'+
'<text:a xlink:href="%s" xlink:type="simple">%s</text:a>'+
'</text:p>', [target, txt]);
end else
textp := '<text:p>' + txt + '</text:p>';

View File

@ -1249,7 +1249,6 @@ end;
-------------------------------------------------------------------------------}
procedure TsWorksheet.CalcFormulas;
var
node: TAVLTreeNode;
cell: PCell;
begin
// prevent infinite loop due to triggering of formula calculation whenever
@ -1257,23 +1256,15 @@ begin
inc(FWorkbook.FCalculationLock);
try
// Step 1 - mark all formula cells as "not calculated"
node := FCells.FindLowest;
while Assigned(node) do begin
cell := PCell(node.Data);
for cell in FCells do
if HasFormula(cell) then
SetCalcState(cell, csNotCalculated);
node := FCells.FindSuccessor(node);
end;
// Step 2 - calculate cells. If a not-yet-calculated cell is found it is
// calculated and then marked as such.
node := FCells.FindLowest;
while Assigned(node) do begin
cell := PCell(node.Data);
if (cell^.ContentType <> cctError) and HasFormula(cell) then
for cell in FCells do
if HasFormula(cell) and (cell^.ContentType <> cctError) then
CalcFormula(cell);
node := FCells.FindSuccessor(node);
end;
finally
dec(FWorkbook.FCalculationLock);

View File

@ -24,12 +24,14 @@ type
DeleteRow: Integer;
Formula: String;
SollFormula: String;
{
SharedFormulaRowCount: Integer; // Size of shared formula block before insert/delete
SharedFormulaColCount: Integer;
SharedFormulaBaseCol_After: Integer; // Position of shared formula base after insert/delete
SharedFormulaBaseRow_After: Integer;
SharedFormulaRowCount_After: Integer; // Size of shared formula block after insert/delete
SharedFormulaColCount_After: Integer;
}
MergedColCount: Integer; // size of merged block before insert/delete
MergedRowCount: Integer;
MergedColCount_After: Integer; // size of merged block after insert/delete
@ -237,12 +239,14 @@ begin
DeleteRow := -1;
Formula := '';
SollFormula := '';
{
SharedFormulaColCount := 0;
SharedFormulaRowCount := 0;
SharedFormulaBaseCol_After := -1;
SharedFormulaBaseRow_After := -1;
SharedFormulaColCount_After := 0;
SharedFormulaRowCount_After := 0;
}
MergedColCount := 0;
MergedRowCount := 0;
end;
@ -931,16 +935,17 @@ var
r1,c1,r2,c2: Cardinal;
MyCell: PCell;
TempFile: string; //write xls/xml to this file and read back from it
L, LL: TStringList;
L: TStringList;
s: String;
expected: String;
actual: String;
expectedFormulas: array of array of String;
// expectedFormulas: array of array of String;
begin
TempFile := GetTempFileName;
L := TStringList.Create;
try
{
// Extract soll formulas into a 2D array in case of shared formulas
if (InsDelTestData[ATestIndex].SharedFormulaRowCount_After > 0) or
(InsDelTestData[ATestIndex].SharedFormulaColCount_After > 0) then
@ -963,7 +968,7 @@ begin
LL.Free;
end;
end;
}
L.Delimiter := '|';
L.StrictDelimiter := true;
L.DelimitedText := InsDelTestData[ATestIndex].Layout;
@ -1047,6 +1052,7 @@ begin
end;
if HasFormula(MyCell) then
begin
{
if (InsDelTestData[ATestIndex].SharedFormulaRowCount_After > 0) or
(InsDelTestData[ATestIndex].SharedFormulaColCount_After > 0)
then
@ -1057,6 +1063,7 @@ begin
'Shared formula mismatch, cell ' + CellNotation(MyWorksheet, Row, Col)
)
else
}
CheckEquals(
InsDelTestData[ATestIndex].SollFormula,
MyWorksheet.ReadFormulaAsString(MyCell),

View File

@ -66,6 +66,7 @@ type
FFillList: TFPList;
FBorderList: TFPList;
FHyperlinkList: TFPList;
FSharedFormulaBaseList: TFPList;
FThemeColors: array of TsColorValue;
FWrittenByFPS: Boolean;
procedure ApplyCellFormatting(ACell: PCell; XfIndex: Integer);
@ -468,6 +469,7 @@ begin
FHyperlinkList := TFPList.Create;
FCellFormatList := TsCellFormatList.Create(true);
// Allow duplicates because xf indexes used in cell records cannot be found any more.
FSharedFormulaBaseList := TFPList.Create;
FPointSeparatorSettings := DefaultFormatSettings;
FPointSeparatorSettings.DecimalSeparator := '.';
@ -487,6 +489,7 @@ begin
FHyperlinkList.Free;
FSharedStrings.Free;
FSharedFormulaBaseList.Free; // Don't free items, they are worksheet cells
// FCellFormatList and FFontList are destroyed by ancestor
@ -664,7 +667,7 @@ procedure TsSpreadOOXMLReader.ReadCell(ANode: TDOMNode; AWorksheet: TsWorksheet)
var
addr, s: String;
rowIndex, colIndex: Cardinal;
cell: PCell;
cell, sharedformulabase: PCell;
datanode: TDOMNode;
dataStr: String;
formulaStr: String;
@ -716,13 +719,21 @@ begin
begin
// Shared formula
s := GetAttrValue(datanode, 'ref');
if (s <> '') then // This is the shared formula range
if (s <> '') then // This defines 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);
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);
end else
begin
// Get index into the SharedFormulaBaseList
s := GetAttrValue(datanode, 'si');
if s <> '' then
begin
sharedformulabase := PCell(FSharedFormulaBaseList[StrToInt(s)]);
FWorksheet.CopyFormula(sharedformulabase, rowindex, colindex);
end;
end;
end
else
@ -735,8 +746,10 @@ begin
// get data type
s := GetAttrValue(ANode, 't'); // "t" = data type
if (s = '') and (dataStr = '') then
AWorksheet.WriteBlank(cell)
else
begin
AWorksheet.WriteBlank(cell); // this erases the formula!!!
if formulaStr <> '' then cell^.FormulaValue := formulaStr;
end else
if (s = '') or (s = 'n') then begin
// Number or date/time, depending on format
number := StrToFloat(dataStr, FPointSeparatorSettings);