fpspreadsheet: Read non-contiguous shared formulas correctly from OOXLM (BIFF8 still faulty)

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3588 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-09-22 10:51:33 +00:00
parent ccb7862c6b
commit 094bb314fc
2 changed files with 62 additions and 8 deletions

View File

@@ -5113,7 +5113,7 @@ var
cellnode: TAVLTreeNode; cellnode: TAVLTreeNode;
col: PCol; col: PCol;
i: Integer; i: Integer;
r, c, ic: Cardinal; r, c, cc: Cardinal;
r1, c1, r2, c2: Cardinal; r1, c1, r2, c2: Cardinal;
rLast, cLast: Cardinal; rLast, cLast: Cardinal;
cell, nextcell, gapcell, oldbase, newbase: PCell; cell, nextcell, gapcell, oldbase, newbase: PCell;
@@ -5160,7 +5160,38 @@ begin
gapcell := GetCell(r, ACol); gapcell := GetCell(r, ACol);
gapcell^.Mergebase := cell^.MergeBase; gapcell^.Mergebase := cell^.MergeBase;
end; end;
end
else
// A shared formula block is found immediately to the left of the
// inserted column. If it extends to the right we have to create a new
// shared formula base in the upper left cell. Note: Excel does not
// extend the shared formula to the inserted column.
if cell^.SharedFormulaBase <> nil then begin
oldbase := cell^.SharedFormulaBase;
// Does it extend to the right of the new column?
nextcell := FindCell(r, ACol+1);
if Assigned(nextcell) and (nextcell^.SharedFormulaBase = oldbase) then
begin
// Yes.
// It next cell is in the top row of the block we make it a shared formula base
if r = oldbase^.Row then
begin
newbase := nextcell;
nextcell^.SharedFormulaBase := nextcell;
nextcell^.FormulaValue := InsertColToFormula(ACol, oldbase); // ??
// Note: the references are not correct here - we fix that later!
end;
// Use the new shared formulabase in all cells of the old block at the right
for cc := ACol+1 to cLast do
begin
cell := FindCell(r, cc);
if (cell = nil) or (cell^.SharedFormulaBase <> oldbase) then
break;
cell^.SharedFormulaBase := newbase;
end;
end;
end; end;
(* (*
else else
// A shared formula block is found immediately before the inserted column // A shared formula block is found immediately before the inserted column
@@ -5198,6 +5229,8 @@ begin
*) *)
end; end;
// Fix shared formulas:
// A shared formula block may break into two pieces if cell references Cell references to the left and to the right of
// Seek along the column immediately to the left of the inserted column // Seek along the column immediately to the left of the inserted column
c := ACol - 1; c := ACol - 1;
for r := 0 to rLast do for r := 0 to rLast do
@@ -5228,9 +5261,9 @@ begin
end; end;
// Now link all cells to the right of the new column (which still // Now link all cells to the right of the new column (which still
// use the old base) to the new base // use the old base) to the new base
for ic := ACol+1 to cLast do for cc := ACol+1 to cLast do
begin begin
cell := FindCell(r, ic); cell := FindCell(r, cc);
if (cell = nil) or (cell^.SharedFormulaBase <> oldbase) then if (cell = nil) or (cell^.SharedFormulaBase <> oldbase) then
break; break;
cell^.SharedFormulaBase := newbase; cell^.SharedFormulaBase := newbase;

View File

@@ -65,6 +65,7 @@ type
FFillList: TFPList; FFillList: TFPList;
FBorderList: TFPList; FBorderList: TFPList;
FThemeColors: array of TsColorValue; FThemeColors: array of TsColorValue;
FSharedFormulas: TStringList;
FWrittenByFPS: Boolean; FWrittenByFPS: Boolean;
procedure ReadBorders(ANode: TDOMNode); procedure ReadBorders(ANode: TDOMNode);
procedure ReadCell(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure ReadCell(ANode: TDOMNode; AWorksheet: TsWorksheet);
@@ -395,6 +396,8 @@ begin
// Set up the default palette in order to have the default color names correct. // Set up the default palette in order to have the default color names correct.
Workbook.UseDefaultPalette; Workbook.UseDefaultPalette;
FSharedFormulas := TStringList.Create;
FSharedStrings := TStringList.Create; FSharedStrings := TStringList.Create;
FFillList := TFPList.Create; FFillList := TFPList.Create;
FBorderList := TFPList.Create; FBorderList := TFPList.Create;
@@ -418,6 +421,7 @@ begin
FBorderList.Free; FBorderList.Free;
FSharedStrings.Free; FSharedStrings.Free;
FSharedFormulas.Free;
inherited Destroy; inherited Destroy;
end; end;
@@ -610,7 +614,7 @@ end;
procedure TsSpreadOOXMLReader.ReadCell(ANode: TDOMNode; AWorksheet: TsWorksheet); procedure TsSpreadOOXMLReader.ReadCell(ANode: TDOMNode; AWorksheet: TsWorksheet);
var var
s: String; addr, s: String;
rowIndex, colIndex: Cardinal; rowIndex, colIndex: Cardinal;
cell: PCell; cell: PCell;
datanode: TDOMNode; datanode: TDOMNode;
@@ -623,8 +627,8 @@ begin
exit; exit;
// get row and column address // get row and column address
s := GetAttrValue(ANode, 'r'); // cell address, like 'A1' addr := GetAttrValue(ANode, 'r'); // cell address, like 'A1'
ParseCellString(s, rowIndex, colIndex); ParseCellString(addr, rowIndex, colIndex);
// create cell // create cell
if FIsVirtualMode then if FIsVirtualMode then
@@ -656,11 +660,28 @@ begin
s := GetAttrValue(datanode, 't'); s := GetAttrValue(datanode, 't');
if s = 'shared' then if s = 'shared' then
begin begin
// Shared formula
s := GetAttrValue(datanode, 'ref'); s := GetAttrValue(datanode, 'ref');
if (s <> '') then if (s <> '') then // This is the shared formula base
AWorksheet.WriteSharedFormula(s, formulaStr); begin
s := GetAttrValue(datanode, 'si');
if s <> '' then
FSharedFormulas.AddObject(addr, Pointer(PtrInt(StrToInt(s))));
FWorksheet.WriteFormula(cell, formulaStr);
cell^.SharedFormulaBase := cell;
//AWorksheet.WriteSharedFormula(s, formulaStr);
end else
begin
s := GetAttrValue(datanode, 'si');
if s <> '' then
begin
s := FSharedFormulas[FSharedFormulas.IndexOfObject(Pointer(PtrInt(StrToInt(s))))];
cell^.SharedFormulaBase := FWorksheet.FindCell(s);
end;
end;
end end
else else
// "Normal" formula
AWorksheet.WriteFormula(cell, formulaStr); AWorksheet.WriteFormula(cell, formulaStr);
end; end;
datanode := datanode.NextSibling; datanode := datanode.NextSibling;