You've already forked lazarus-ccr
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:
@ -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>';
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user