You've already forked lazarus-ccr
Applied patch from Torsten Bonde Christiansen ( http://bugs.freepascal.org/view.php?id=14480 ) with some minor changes. Big speedup reading spreadsheets.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@952 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -30,7 +30,7 @@ uses
|
||||
Classes, SysUtils,
|
||||
fpszipper, {NOTE: fpszipper is the latest zipper.pp Change to standard zipper when FPC 2.4 is released. Changed by JLJR}
|
||||
fpspreadsheet,
|
||||
xmlread, DOM;
|
||||
xmlread, DOM, AVL_Tree;
|
||||
|
||||
type
|
||||
|
||||
@ -404,6 +404,8 @@ var
|
||||
CurCell: PCell;
|
||||
CurRow: array of PCell;
|
||||
LastColNum: Cardinal;
|
||||
ACell: PCell;
|
||||
AVLNode: TAVLTreeNode;
|
||||
begin
|
||||
LastColNum := CurSheet.GetLastColNumber;
|
||||
|
||||
@ -413,41 +415,30 @@ begin
|
||||
' <table:table-column table:style-name="co1" table:number-columns-repeated="' +
|
||||
IntToStr(LastColNum + 1) + '" table:default-cell-style-name="Default"/>' + LineEnding;
|
||||
|
||||
ACell := GetMem(SizeOf(TCell));
|
||||
|
||||
// The cells need to be written in order, row by row, cell by cell
|
||||
for j := 0 to CurSheet.GetLastRowNumber do
|
||||
begin
|
||||
FContent := FContent +
|
||||
' <table:table-row table:style-name="ro1">' + LineEnding;
|
||||
|
||||
// First make an array with the cells of this row in their respective order
|
||||
// nil pointers indicate empty cells, so it's necessary to initialize the array
|
||||
SetLength(CurRow, LastColNum + 1);
|
||||
for k := 0 to LastColNum do CurRow[k] := nil;
|
||||
|
||||
// Now fill the array with the cells in their proper place
|
||||
for k := 0 to CurSheet.FCells.Count - 1 do
|
||||
begin
|
||||
CurCell := CurSheet.FCells.Items[k];
|
||||
if CurCell^.Row = j then CurRow[CurCell^.Col] := CurCell;
|
||||
end;
|
||||
|
||||
// And now write all cells from this row
|
||||
// Write cells from this row.
|
||||
for k := 0 to LastColNum do
|
||||
begin
|
||||
CurCell := CurRow[k];
|
||||
|
||||
if CurCell = nil then
|
||||
FContent := FContent + '<table:table-cell/>' + LineEnding
|
||||
else WriteCellCallback(CurCell, nil);
|
||||
ACell^.Row := j;
|
||||
ACell^.Col := k;
|
||||
AVLNode := CurSheet.Cells.Find(ACell);
|
||||
if Assigned(AVLNode) then
|
||||
WriteCellCallback(PCell(AVLNode.Data), nil)
|
||||
else
|
||||
FContent := FContent + '<table:table-cell/>' + LineEnding;
|
||||
end;
|
||||
|
||||
FContent := FContent +
|
||||
' </table:table-row>' + LineEnding;
|
||||
end;
|
||||
|
||||
// Clean up
|
||||
SetLength(CurRow, 0);
|
||||
|
||||
// Footer
|
||||
FContent := FContent +
|
||||
' </table:table>' + LineEnding;
|
||||
|
@ -14,7 +14,7 @@ unit fpspreadsheet;
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils;
|
||||
Classes, SysUtils, AVL_Tree;
|
||||
|
||||
type
|
||||
TsSpreadsheetFormat = (sfExcel2, sfExcel3, sfExcel4, sfExcel5, sfExcel8,
|
||||
@ -98,9 +98,9 @@ type
|
||||
|
||||
TsWorksheet = class
|
||||
private
|
||||
FCells: TAvlTree;
|
||||
procedure RemoveCallback(data, arg: pointer);
|
||||
public
|
||||
FCells: TFPList;
|
||||
Name: string;
|
||||
{ Base methods }
|
||||
constructor Create;
|
||||
@ -109,7 +109,6 @@ type
|
||||
function FindCell(ARow, ACol: Cardinal): PCell;
|
||||
function GetCell(ARow, ACol: Cardinal): PCell;
|
||||
function GetCellCount: Cardinal;
|
||||
function GetCellByIndex(AIndex: Cardinal): PCell;
|
||||
function GetLastColNumber: Cardinal;
|
||||
function GetLastRowNumber: Cardinal;
|
||||
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
|
||||
@ -118,6 +117,7 @@ type
|
||||
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double);
|
||||
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
|
||||
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
|
||||
property Cells: TAVLTree read FCells;
|
||||
end;
|
||||
|
||||
{ TsWorkbook }
|
||||
@ -178,7 +178,7 @@ type
|
||||
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
|
||||
{ General writing methods }
|
||||
procedure WriteCellCallback(data, arg: pointer);
|
||||
procedure WriteCellsToStream(AStream: TStream; ACells: TFPList);
|
||||
procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
|
||||
procedure WriteToFile(AFileName: string; AData: TsWorkbook); virtual;
|
||||
procedure WriteToStream(AStream: TStream; AData: TsWorkbook); virtual;
|
||||
{ Record writing methods }
|
||||
@ -206,6 +206,9 @@ procedure RegisterSpreadFormat(
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
Math;
|
||||
|
||||
var
|
||||
{ Translatable strings }
|
||||
lpUnsupportedReadFormat, lpUnsupportedWriteFormat: string;
|
||||
@ -241,6 +244,13 @@ begin
|
||||
FreeMem(data);
|
||||
end;
|
||||
|
||||
function CompareCells(Item1, Item2: Pointer): Integer;
|
||||
begin
|
||||
result := PCell(Item1).Row - PCell(Item2).Row;
|
||||
if Result = 0 then
|
||||
Result := PCell(Item1).Col - PCell(Item2).Col;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Constructor.
|
||||
}
|
||||
@ -248,7 +258,7 @@ constructor TsWorksheet.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
|
||||
FCells := TFPList.Create;
|
||||
FCells := TAVLTree.Create(@CompareCells);
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -277,24 +287,16 @@ end;
|
||||
}
|
||||
function TsWorksheet.FindCell(ARow, ACol: Cardinal): PCell;
|
||||
var
|
||||
i: Integer;
|
||||
ACell: PCell;
|
||||
LCell: TCell;
|
||||
AVLNode: TAVLTreeNode;
|
||||
begin
|
||||
i := 0;
|
||||
Result := nil;
|
||||
|
||||
while (i < FCells.Count) do
|
||||
begin
|
||||
ACell := PCell(FCells.Items[i]);
|
||||
|
||||
if (ACell^.Row = ARow) and (ACell^.Col = ACol) then
|
||||
begin
|
||||
Result := ACell;
|
||||
Exit;
|
||||
end;
|
||||
|
||||
Inc(i);
|
||||
end;
|
||||
|
||||
LCell.Row := ARow;
|
||||
LCell.Col := ACol;
|
||||
AVLNode := Cells.Find(@LCell);
|
||||
if Assigned(AVLNode) then
|
||||
result := PCell(AVLNode.Data);
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -326,7 +328,7 @@ begin
|
||||
Result^.Row := ARow;
|
||||
Result^.Col := ACol;
|
||||
|
||||
FCells.Add(Result);
|
||||
Cells.Add(Result);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -343,28 +345,7 @@ end;
|
||||
}
|
||||
function TsWorksheet.GetCellCount: Cardinal;
|
||||
begin
|
||||
Result := FCells.Count;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Obtains the cell with a specific index in the internal list of cells.
|
||||
|
||||
The index goes from 0 to GetCellCount - 1.
|
||||
|
||||
This routine is used together with GetCellCount to
|
||||
iterate througth all cells in a worksheet efficiently.
|
||||
|
||||
@param AIndex The index of the cell to be obtained
|
||||
|
||||
@return A pointer to the cell, or nil if it doesn't exist
|
||||
|
||||
@see TCell
|
||||
@see GetCellCount
|
||||
}
|
||||
function TsWorksheet.GetCellByIndex(AIndex: Cardinal): PCell;
|
||||
begin
|
||||
if FCells.Count > AIndex then Result := PCell(FCells.Items[AIndex])
|
||||
else Result := nil;
|
||||
Result := Cells.Count;
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -379,19 +360,18 @@ end;
|
||||
}
|
||||
function TsWorksheet.GetLastColNumber: Cardinal;
|
||||
var
|
||||
i: Integer;
|
||||
ACell: PCell;
|
||||
AVLNode: TAVLTreeNode;
|
||||
begin
|
||||
i := 0;
|
||||
Result := 0;
|
||||
|
||||
while (i < FCells.Count) do
|
||||
// Traverse the tree from lowest to highest.
|
||||
// Since tree primary sort order is on Row
|
||||
// highest Col could exist anywhere.
|
||||
AVLNode := Cells.FindLowest;
|
||||
While Assigned(AVLNode) do
|
||||
begin
|
||||
ACell := PCell(FCells.Items[i]);
|
||||
|
||||
if ACell^.Col > Result then Result := ACell^.Col;
|
||||
|
||||
Inc(i);
|
||||
Result := Math.Max(Result, PCell(AVLNode.Data)^.Col);
|
||||
AVLNode := Cells.FindSuccessor(AVLNode);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -407,20 +387,13 @@ end;
|
||||
}
|
||||
function TsWorksheet.GetLastRowNumber: Cardinal;
|
||||
var
|
||||
i: Integer;
|
||||
ACell: PCell;
|
||||
AVLNode: TAVLTreeNode;
|
||||
begin
|
||||
i := 0;
|
||||
Result := 0;
|
||||
|
||||
while (i < FCells.Count) do
|
||||
begin
|
||||
ACell := PCell(FCells.Items[i]);
|
||||
|
||||
if ACell^.Row > Result then Result := ACell^.Row;
|
||||
|
||||
Inc(i);
|
||||
end;
|
||||
AVLNode := FCells.FindHighest;
|
||||
if Assigned(AVLNode) then
|
||||
Result := PCell(AVLNode.Data).Row;
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -460,8 +433,16 @@ end;
|
||||
Clears the list of Cells and releases their memory.
|
||||
}
|
||||
procedure TsWorksheet.RemoveAllCells;
|
||||
var
|
||||
Node: TAVLTreeNode;
|
||||
begin
|
||||
FCells.ForEachCall(RemoveCallback, nil);
|
||||
Node:=FCells.FindLowest;
|
||||
while Assigned(Node) do begin
|
||||
RemoveCallback(Node.Data,nil);
|
||||
Node.Data:=nil;
|
||||
Node:=FCells.FindSuccessor(Node);
|
||||
end;
|
||||
FCells.Clear;
|
||||
end;
|
||||
|
||||
{@@
|
||||
@ -725,7 +706,7 @@ end;
|
||||
}
|
||||
function TsWorkbook.GetWorksheetByIndex(AIndex: Cardinal): TsWorksheet;
|
||||
begin
|
||||
if AIndex < FWorksheets.Count then Result := TsWorksheet(FWorksheets.Items[AIndex])
|
||||
if (integer(AIndex) < FWorksheets.Count) and (integer(AIndex)>=0) then Result := TsWorksheet(FWorksheets.Items[AIndex])
|
||||
else Result := nil;
|
||||
end;
|
||||
|
||||
@ -854,9 +835,16 @@ end;
|
||||
@param AStream The output stream.
|
||||
@param ACells List of cells to be writeen
|
||||
}
|
||||
procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream; ACells: TFPList);
|
||||
procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
|
||||
var
|
||||
AVLNode: TAVLTreeNode;
|
||||
begin
|
||||
ACells.ForEachCall(WriteCellCallback, Pointer(AStream));
|
||||
AVLNode := ACells.FindLowest;
|
||||
While Assigned(AVLNode) do
|
||||
begin
|
||||
WriteCellCallback(AVLNode.Data, Pointer(AStream));
|
||||
AVLNode := ACells.FindSuccessor(AVLNode);
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@
|
||||
|
@ -130,7 +130,7 @@ procedure TsSpreadBIFF2Writer.WriteToStream(AStream: TStream; AData: TsWorkbook)
|
||||
begin
|
||||
WriteBOF(AStream);
|
||||
|
||||
WriteCellsToStream(AStream, AData.GetFirstWorksheet.FCells);
|
||||
WriteCellsToStream(AStream, AData.GetFirstWorksheet.Cells);
|
||||
|
||||
WriteEOF(AStream);
|
||||
end;
|
||||
|
@ -403,7 +403,7 @@ begin
|
||||
|
||||
WriteWindow2(AStream, True);
|
||||
|
||||
WriteCellsToStream(AStream, AData.GetWorksheetByIndex(i).FCells);
|
||||
WriteCellsToStream(AStream, AData.GetWorksheetByIndex(i).Cells);
|
||||
|
||||
WriteEOF(AStream);
|
||||
end;
|
||||
|
@ -370,7 +370,7 @@ begin
|
||||
|
||||
WriteWindow2(AStream, True);
|
||||
|
||||
WriteCellsToStream(AStream, AData.GetWorksheetByIndex(i).FCells);
|
||||
WriteCellsToStream(AStream, AData.GetWorksheetByIndex(i).Cells);
|
||||
|
||||
WriteEOF(AStream);
|
||||
end;
|
||||
|
Reference in New Issue
Block a user