fpspreadsheet: Patch from bug 19884, improves the format detection of the reader and adds a writer format auto-detector

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1797 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2011-08-11 14:30:25 +00:00
parent 93503cda15
commit d8ff486769

View File

@ -25,6 +25,7 @@ const
STR_EXCEL_EXTENSION = '.xls'; STR_EXCEL_EXTENSION = '.xls';
STR_OOXML_EXCEL_EXTENSION = '.xlsx'; STR_OOXML_EXCEL_EXTENSION = '.xlsx';
STR_OPENDOCUMENT_CALC_EXTENSION = '.ods'; STR_OPENDOCUMENT_CALC_EXTENSION = '.ods';
STR_COMMA_SEPARATED_EXTENSION = '.csv';
type type
@ -222,6 +223,7 @@ type
{ Base methods } { Base methods }
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
class function GetFormatFromFileName(const AFileName: TFileName; var SheetType: TsSpreadsheetFormat): Boolean;
function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader; function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader;
function CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter; function CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter;
procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat); overload; procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat); overload;
@ -229,7 +231,8 @@ type
procedure ReadFromStream(AStream: TStream; AFormat: TsSpreadsheetFormat); procedure ReadFromStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
procedure WriteToFile(const AFileName: string; procedure WriteToFile(const AFileName: string;
const AFormat: TsSpreadsheetFormat; const AFormat: TsSpreadsheetFormat;
const AOverwriteExisting: Boolean = False); const AOverwriteExisting: Boolean = False); overload;
procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False); overload;
procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat); procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
{ Worksheet list handling methods } { Worksheet list handling methods }
function AddWorksheet(AName: string): TsWorksheet; function AddWorksheet(AName: string): TsWorksheet;
@ -315,8 +318,6 @@ procedure RegisterSpreadFormat(
AWriterClass: TsSpreadWriterClass; AWriterClass: TsSpreadWriterClass;
AFormat: TsSpreadsheetFormat); AFormat: TsSpreadsheetFormat);
implementation implementation
uses uses
@ -364,6 +365,7 @@ begin
Result := PCell(Item1).Col - PCell(Item2).Col; Result := PCell(Item1).Col - PCell(Item2).Col;
end; end;
{@@ {@@
Constructor. Constructor.
} }
@ -767,6 +769,24 @@ begin
inherited Destroy; inherited Destroy;
end; end;
{@@
Helper method for determining the spreadsheet type from the file type extension
Returns: True if the file matches any of the known formats, false otherwise
}
class function TsWorkbook.GetFormatFromFileName(const AFileName: TFileName; var SheetType: TsSpreadsheetFormat): Boolean;
var
suffix: String;
begin
Result := True;
suffix := ExtractFileExt(AFileName);
if suffix = STR_EXCEL_EXTENSION then SheetType := sfExcel8
else if suffix = STR_OOXML_EXCEL_EXTENSION then SheetType := sfOOXML
else if suffix = STR_OPENDOCUMENT_CALC_EXTENSION then SheetType := sfOpenDocument
else if suffix = STR_COMMA_SEPARATED_EXTENSION then SheetType := sfCSV
else Result := False;
end;
{@@ {@@
Convenience method which creates the correct Convenience method which creates the correct
reader object for a given spreadsheet format. reader object for a given spreadsheet format.
@ -831,14 +851,39 @@ end;
the extension. In the case of the ambiguous xls extension, it will simply the extension. In the case of the ambiguous xls extension, it will simply
assume that it is BIFF8. Note that it could be BIFF2, 3, 4 or 5 too. assume that it is BIFF8. Note that it could be BIFF2, 3, 4 or 5 too.
} }
procedure TsWorkbook.ReadFromFile(AFileName: string); procedure TsWorkbook.ReadFromFile(AFileName: string); overload;
var var
Str: String; SheetType: TsSpreadsheetFormat;
valid: Boolean;
lException: Exception = nil;
begin begin
Str := ExtractFileExt(AFileName); valid := GetFormatFromFileName(AFileName, SheetType);
if Str = STR_EXCEL_EXTENSION then ReadFromFile(AFileName, sfExcel8) if valid then
else if Str = STR_OOXML_EXCEL_EXTENSION then ReadFromFile(AFileName, sfOOXML) begin
else if Str = STR_OPENDOCUMENT_CALC_EXTENSION then ReadFromFile(AFileName, sfOpenDocument); if SheetType = sfExcel8 then
begin
repeat
try
SheetType := Pred(SheetType);
ReadFromFile(AFileName, SheetType);
valid := True;
except
on E: Exception do
begin
if SheetType = sfExcel8 then lException := E;
valid := False
end;
end;
until valid or (SheetType = sfExcel2);
// A failed attempt to read a file should bring an exception, so re-raise
// the exception if necessary. We re-raise the exception brought by Excel 8,
// since this is the most common format
if (not valid) and (lException <> nil) then raise lException;
end
else
ReadFromFile(AFileName, SheetType);
end;
end; end;
{@@ {@@
@ -877,6 +922,20 @@ begin
end; end;
end; end;
{@@
Writes the document to file based on the extension. If this was an earlier sfExcel type file, it will be upgraded to sfExcel8,
}
procedure TsWorkbook.WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); overload;
var
SheetType: TsSpreadsheetFormat;
valid: Boolean;
begin
valid := GetFormatFromFileName(AFileName, SheetType);
if valid then WriteToFile(AFileName, SheetType, AOverwriteExisting)
else raise Exception.Create(Format(
'[TsWorkbook.WriteToFile] Attempted to save a spreadsheet by extension, but the extension %s is invalid.', [ExtractFileExt(AFileName)]));
end;
{@@ {@@
Writes the document to a stream Writes the document to a stream
} }