fpspreadsheet: Experiments with ods to/from clipboard

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4362 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-09-26 17:14:10 +00:00
parent 69c34e5687
commit 295db4cdda
2 changed files with 51 additions and 137 deletions

View File

@ -142,7 +142,7 @@ type
destructor Destroy; override;
{ General reading methods }
(* procedure ReadFromFile(AFileName: string); override;*)
procedure ReadFromClipboardStream(AStream: TStream); override;
procedure ReadFromStream(AStream: TStream); override;
end;
@ -229,8 +229,11 @@ type
{ General writing methods }
procedure WriteStringToFile(AString, AFileName: string);
procedure WriteToClipboardStream(AStream: TStream); override;
{
procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); override;
}
procedure WriteToStream(AStream: TStream); override;
end;
@ -2035,131 +2038,12 @@ begin
if FIsVirtualMode then
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
end;
(*
{ In principle, this method could be simplified by calling ReadFromStream which
is essentially a duplication of ReadFromFile. But ReadFromStream leads to
worse memory usage. --> KEEP READFROMFILE INTACT
See fpspeedtest, ods 20k x 100 cells --> out of mem in Win7-32 bit, 4 GB}
procedure TsSpreadOpenDocReader.ReadFromFile(AFileName: string);
var
Doc : TXMLDocument;
FilePath : string;
UnZip : TUnZipper;
FileList : TStringList;
BodyNode, SpreadSheetNode, TableNode: TDOMNode;
StylesNode: TDOMNode;
OfficeSettingsNode: TDOMNode;
nodename: String;
pageLayout: PsPageLayout;
sheet: TsWorksheet;
procedure TsSpreadOpenDocReader.ReadFromClipboardStream(AStream: TStream);
begin
//unzip files into AFileName path
FilePath := GetUniqueTempDir(false);
UnZip := TUnZipper.Create;
FileList := TStringList.Create;
try
FileList.Add('styles.xml');
FileList.Add('content.xml');
FileList.Add('settings.xml');
UnZip.OutputPath := FilePath;
Unzip.UnZipFiles(AFileName,FileList);
finally
FreeAndNil(FileList);
FreeAndNil(UnZip);
end; //try
Doc := nil;
try
// process the styles.xml file
ReadXMLFile(Doc, FilePath+'styles.xml');
DeleteFile(FilePath+'styles.xml');
ReadFontFaces(Doc.DocumentElement.FindNode('office:font-face-decls'));
StylesNode := Doc.DocumentElement.FindNode('office:styles');
ReadNumFormats(StylesNode);
ReadStyles(StylesNode);
StylesNode := Doc.DocumentElement.FindNode('office:automatic-styles');
ReadAutomaticStyles(StylesNode);
StylesNode := Doc.DocumentElement.FindNode('office:master-styles');
ReadMasterStyles(StylesNode);
Doc.Free;
//process the content.xml file
ReadXMLFile(Doc, FilePath+'content.xml');
DeleteFile(FilePath+'content.xml');
ReadFontFaces(Doc.DocumentElement.FindNode('office:font-face-decls'));
StylesNode := Doc.DocumentElement.FindNode('office:automatic-styles');
ReadNumFormats(StylesNode);
ReadStyles(StylesNode);
BodyNode := Doc.DocumentElement.FindNode('office:body');
if not Assigned(BodyNode) then Exit;
SpreadSheetNode := BodyNode.FindNode('office:spreadsheet');
if not Assigned(SpreadSheetNode) then Exit;
ReadDateMode(SpreadSheetNode);
//process each table (sheet)
TableNode := SpreadSheetNode.FindNode('table:table');
while Assigned(TableNode) do
begin
nodename := TableNode.Nodename;
// These nodes occur due to leading spaces which are not skipped
// automatically any more due to PreserveWhiteSpace option applied
// to ReadXMLFile
if nodeName <> 'table:table' then
begin
TableNode := TableNode.NextSibling;
continue;
end;
FWorkSheet := FWorkbook.AddWorksheet(GetAttrValue(TableNode, 'table:name'), true);
// Collect column styles used
ReadColumns(TableNode);
// Process each row inside the sheet and process each cell of the row
ReadRowsAndCells(TableNode);
// Read page layout
pageLayout := ReadPageLayout(StylesNode, GetAttrValue(TableNode, 'table:style-name'));
if pageLayout <> nil then
FWorksheet.PageLayout := pagelayout^;
// Handle columns and rows
ApplyColWidths;
// Page layout
FixCols(FWorksheet);
FixRows(FWorksheet);
// Continue with next table
TableNode := TableNode.NextSibling;
end; //while Assigned(TableNode)
Doc.Free;
// process the settings.xml file (Note: it does not always exist!)
if FileExists(FilePath + 'settings.xml') then
begin
ReadXMLFile(Doc, FilePath+'settings.xml');
DeleteFile(FilePath+'settings.xml');
OfficeSettingsNode := Doc.DocumentElement.FindNode('office:settings');
ReadSettings(OfficeSettingsNode);
end;
// Active sheet
if FActiveSheet <> '' then
sheet := FWorkbook.GetWorksheetByName(FActiveSheet) else
sheet := FWorkbook.GetWorksheetByIndex(0);
FWorkbook.SelectWorksheet(sheet);
finally
RemoveDir(FilePath);
if Assigned(Doc) then Doc.Free;
end;
ReadFromStream(AStream);
end;
*)
procedure TsSpreadOpenDocReader.ReadFromStream(AStream: TStream);
var
Doc : TXMLDocument;
@ -4850,7 +4734,7 @@ begin
TheStream.WriteBuffer(Pointer(S)^,Length(S));
TheStream.Free;
end;
(*
{@@ ----------------------------------------------------------------------------
Writes an OOXML document to a file.
-------------------------------------------------------------------------------}
@ -4874,6 +4758,11 @@ begin
finally
FreeAndNil(lStream);
end;
end; *)
procedure TsSpreadOpenDocWriter.WriteToClipboardStream(AStream: TStream);
begin
WriteToStream(AStream);
end;
procedure TsSpreadOpenDocWriter.WriteToStream(AStream: TStream);
@ -6233,7 +6122,7 @@ initialization
{@@ ----------------------------------------------------------------------------
Registers this reader / writer on fpSpreadsheet
-------------------------------------------------------------------------------}
RegisterSpreadFormat(TsSpreadOpenDocReader, TsSpreadOpenDocWriter, sfOpenDocument);
RegisterSpreadFormat(TsSpreadOpenDocReader, TsSpreadOpenDocWriter, sfOpenDocument, true, true);
end.

View File

@ -465,7 +465,8 @@ procedure Register;
implementation
uses
Types, Math, StrUtils, TypInfo, LCLType, LCLProc, Dialogs, Forms, Clipbrd,
Types, Math, StrUtils, TypInfo, LCLType, LCLIntf, LCLProc,
Dialogs, Forms, Clipbrd,
fpsStrings, fpsUtils, fpsNumFormat, fpsHTMLUtils, fpsCSV;
var
@ -474,6 +475,7 @@ var
cfHTMLFormat: Integer = 0;
cfTextHTMLFormat: Integer = 0;
cfCSVFormat: Integer = 0;
cfOpenDocumentFormat: Integer = 0;
{@@ ----------------------------------------------------------------------------
Registers the spreadsheet components in the Lazarus component palette,
@ -1140,11 +1142,9 @@ end;
-------------------------------------------------------------------------------}
procedure TsWorkbookSource.CopyCellsToClipboard;
var
r,c,i: Integer;
sel: TsCellRangeArray;
cell: PCell;
stream: TStream;
csv: TsCSVParams;
savedCSVParams: TsCSVParams;
begin
sel := FWorksheet.GetSelection;
if Length(sel) = 0 then
@ -1156,7 +1156,13 @@ begin
stream := TMemoryStream.Create;
try
// At first write BIFF8 format
// Write OpenDocument format
FWorkbook.CopyToClipboardStream(stream, sfOpenDocument);
if cfOpenDocumentFormat <> 0 then
Clipboard.AddFormat(cfOpenDocumentFormat, stream);
(stream as TMemoryStream).Clear;
// Write BIFF8 format
FWorkbook.CopyToClipboardStream(stream, sfExcel8);
if cfBiff8Format <> 0 then
Clipboard.AddFormat(cfBiff8Format, stream);
@ -1177,7 +1183,7 @@ begin
(stream as TMemoryStream).Clear;
// Then write CSV format
csv := CSVParams;
savedCSVParams := CSVParams;
CsvParams.Delimiter := ';';
CsvParams.AutoDetectNumberFormat := false;
CsvParams.SheetIndex := FWorkbook.GetWorksheetIndex(FWorkbook.ActiveWorksheet);
@ -1190,7 +1196,7 @@ begin
CsvParams.Delimiter := #9;
FWorkbook.CopyToClipboardStream(stream, sfCSV);
Clipboard.AddFormat(CF_TEXT, stream);
CSVParams := csv;
CSVParams := savedCSVParams;
(stream as TMemoryStream).Clear;
// To do: XML format
@ -1258,13 +1264,17 @@ begin
stream := TMemoryStream.Create;
try
// Check whether the clipboard content is suitable for fpspreadsheet
if Clipboard.GetFormat(cfBiff8Format, stream) then
if Clipboard.GetFormat(cfOpenDocumentFormat, stream) then
fmt := sfOpenDocument
else if Clipboard.GetFormat(cfBiff8Format, stream) then
fmt := sfExcel8
else if Clipboard.GetFormat(cfBiff5Format, stream) then
fmt := sfExcel5
else if Clipboard.GetFormat(cfHTMLFormat, stream) or Clipboard.GetFormat(cfTextHTMLFormat, stream) then
fmt := sfHTML
else if Clipboard.GetFormat(cfCSVFormat, stream) or Clipboard.GetFormat(CF_TEXT, stream) then
else if Clipboard.GetFormat(cfCSVFormat, stream) then //or Clipboard.GetFormat(CF_TEXT, stream) then
fmt := sfCSV
else if Clipboard.GetFormat(PredefinedClipboardFormat(pcfText), stream) then
fmt := sfCSV
else begin
// Exit if there are no spreadsheet data in clipboard
@ -3183,13 +3193,28 @@ initialization
RegisterPropertyToSkip(TsSpreadsheetInspector, 'RowHeights', 'For compatibility with older Laz versions.', '');
RegisterPropertyToSkip(TsSpreadsheetInspector, 'ColWidths', 'For compatibility with older Laz versions.', '');
cfBiff8Format := RegisterClipboardFormat('Biff8');
(*
{$IFDEF MSWINDOWS}
cfOpenDocumentFormat := RegisterClipboardFormat('Star Embed Source (XML)');
{$ELSE}
cfOpenDocumentFormat := RegisterClipboardFormat('application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)');
{$ENDIF}
*)
cfOpenDocumentFormat := RegisterClipboardFormat('application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)"');
// cfOpenDocumentFormat := RegisterClipboardFormat('application/x-openoffice;windows_formatname="Star Embed Source (XML)"');
//cfOpenDocumentFormat := RegisterClipboardFormat('Star Embed Source (XML)');
// cfBiff8Format := RegisterClipboardFormat('application/vnd.ms-excel'); //Biff8');
cfBiff8Format := RegisterclipboardFormat('Biff8');
cfBiff5Format := RegisterClipboardFormat('Biff5');
cfHTMLFormat := RegisterClipboardFormat('HTML Format');
cfTextHTMLFormat := RegisterClipboardFormat('text/html');
cfCSVFormat := RegisterClipboardFormat('CSV');
// xls: application/vnd.ms-excel
// xlsx: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
// ods: application/x-openoffice-embed-source-xml;windows_formatname="Star Embed Source (XML)" -- Linux -- tested
// ods: Star Embed Source (XML) -- Windows
finalization
// CellClipboard.Free;