fpspreadsheet: Add code for copying to clipboard (fpsCtrls), initial version only handles biff8 and biff5 formats.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4354 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2015-09-23 21:40:32 +00:00
parent 6a82944c1c
commit ad8daec47c
6 changed files with 140 additions and 15 deletions

View File

@ -591,6 +591,9 @@ type
{@@ The workbook contains the worksheets and provides methods for reading from
and writing to file.
}
{ TsWorkbook }
TsWorkbook = class
private
{ Internal data }
@ -653,7 +656,8 @@ type
class function GetFormatFromFileHeader(AStream: TStream;
out SheetType: TsSpreadsheetFormat): Boolean; overload;
function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsBasicSpreadReader;
function CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsBasicSpreadWriter;
function CreateSpreadWriter(AFormat: TsSpreadsheetFormat;
AClipboardMode: Boolean = false): TsBasicSpreadWriter;
procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat); overload;
procedure ReadFromFile(AFileName: string); overload;
procedure ReadFromFileIgnoringExtension(AFileName: string);
@ -662,7 +666,7 @@ type
const AFormat: TsSpreadsheetFormat;
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; AClipboardMode: Boolean = false);
{ Worksheet list handling methods }
function AddWorksheet(AName: string;
@ -720,6 +724,9 @@ type
function AddNumberFormat(AFormatStr: String): Integer;
function GetNumberFormat(AIndex: Integer): TsNumFormatParams;
function GetNumberFormatCount: Integer;
{ Clipboard }
procedure CopyToClipboardStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
(*
{ Color handling }
function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String;
@ -810,6 +817,7 @@ type
TsBasicSpreadReader = class(TsBasicSpreadReaderWriter)
public
{ General writing methods }
procedure ReadFromClipboardStream(AStream: TStream); virtual; abstract;
procedure ReadFromFile(AFileName: string); virtual; abstract;
procedure ReadFromStream(AStream: TStream); virtual; abstract;
procedure ReadFromStrings(AStrings: TStrings); virtual; abstract;
@ -821,6 +829,7 @@ type
{ Helpers }
procedure CheckLimitations; virtual;
{ General writing methods }
procedure WriteToClipboardStream(AStream: TStream); virtual; abstract;
procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); virtual; abstract;
procedure WriteToStream(AStream: TStream); virtual; abstract;
@ -6618,19 +6627,23 @@ end;
Convenience method which creates the correct writer object for a given
spreadsheet format.
@param AFormat File format to be used for writing the workbook
@param AFormat File format to be used for writing the workbook
@param AClipboardMode If TRUE then special data are written for usage in the
clipboard
@return An instance of a TsCustomSpreadWriter descendent which is able to
write the given file format.
-------------------------------------------------------------------------------}
function TsWorkbook.CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsBasicSpreadWriter;
function TsWorkbook.CreateSpreadWriter(AFormat: TsSpreadsheetFormat;
AClipboardMode: Boolean = false): TsBasicSpreadWriter;
var
i: Integer;
begin
Result := nil;
for i := 0 to Length(GsSpreadFormats) - 1 do
if GsSpreadFormats[i].Format = AFormat then
if (GsSpreadFormats[i].Format = AFormat) and
(AClipboardMode or GsSpreadFormats[i].CanWriteToClipboard) then
begin
Result := GsSpreadFormats[i].WriterClass.Create(self);
Break;
@ -6890,19 +6903,23 @@ end;
{@@ ----------------------------------------------------------------------------
Writes the document to a stream
@param AStream Instance of the stream being written to
@param AFormat File format to be written.
@param AStream Instance of the stream being written to
@param AFormat File format to be written.
@param AClipboardMode Stream will be used by calling method for clipboard access
-------------------------------------------------------------------------------}
procedure TsWorkbook.WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
procedure TsWorkbook.WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat;
AClipboardMode: Boolean = false);
var
AWriter: TsBasicSpreadWriter;
begin
AWriter := CreateSpreadWriter(AFormat);
AWriter := CreateSpreadWriter(AFormat, AClipboardMode);
try
PrepareBeforeSaving;
AWriter.CheckLimitations;
FReadWriteFlag := rwfWrite;
AWriter.WriteToStream(AStream);
if AClipboardMode then
AWriter.WriteToClipboardStream(AStream) else
AWriter.WriteToStream(AStream);
finally
FReadWriteFlag := rwfNormal;
AWriter.Free;
@ -7715,6 +7732,60 @@ function TsWorkbook.GetNumberFormatCount: Integer;
begin
Result := FNumFormatList.Count;
end;
{@@ ----------------------------------------------------------------------------
Writes the selected cells to a stream for usage in the clipboard.
Transfer to the clipboard has do be done by the calling routine since
fpspreadsheet does not "know" the system's clipboard.
-------------------------------------------------------------------------------}
procedure TsWorkbook.CopyToClipboardStream(AStream: TStream;
AFormat: TsSpreadsheetFormat);
var
clipbook: TsWorkbook;
clipsheet: TsWorksheet;
sel: TsCellRange;
r, c: Cardinal;
srccell, destcell: PCell;
begin
if AStream = nil then
exit;
if ActiveWorksheet = nil then
exit;
// Create workbook which will be written to clipboard stream
// Contains only the selected worksheet and the selected cells.
clipbook := TsWorkbook.Create;
try
clipsheet := clipbook.AddWorksheet(ActiveWorksheet.Name);
for sel in ActiveWorksheet.GetSelection do
begin
for r := sel.Row1 to sel.Row2 do
for c := sel.Col1 to sel.Col2 do
begin
srccell := ActiveWorksheet.FindCell(r, c);
if srccell <> nil then begin
destcell := clipsheet.AddCell(r, c);
clipsheet.CopyCell(srccell, destcell);
end;
end;
end;
// Select the same cells as in the source workbook.
clipsheet.SetSelection(ActiveWorksheet.GetSelection);
clipsheet.SelectCell(ActiveWorksheet.ActiveCellRow, ActiveWorksheet.ActiveCellCol);
// Write this workbook to a stream. Set the last parameter (ClipboardMode)
// to TRUE to use the dedicated clipboard routine.
clipbook.WriteToStream(AStream, AFormat, true);
// The calling routine which copies the stream to the clipboard requires
// the stream to be at its beginning.
AStream.Position := 0;
finally
clipbook.Free;
end;
end;
(*
{@@ ----------------------------------------------------------------------------
Adds a color to the palette and returns its palette index, but only if the

View File

@ -467,9 +467,13 @@ procedure Register;
implementation
uses
Types, Math, StrUtils, TypInfo, LCLType, LCLProc, Dialogs, Forms,
Types, Math, StrUtils, TypInfo, LCLType, LCLProc, Dialogs, Forms, Clipbrd,
fpsStrings, fpsUtils, fpsNumFormat, fpsHTMLUtils;
var
cfBiff8Format: Integer = 0;
cfBiff5Format: Integer = 0;
{@@ ----------------------------------------------------------------------------
Registers the spreadsheet components in the Lazarus component palette,
page "FPSpreadsheet".
@ -1145,7 +1149,43 @@ var
r,c,i: Integer;
sel: TsCellRangeArray;
cell: PCell;
stream: TStream;
begin
Clipboard.Open;
try
Clipboard.Clear;
// Ensure the 'Biff8' clipboard format is registered
cfBiff8Format := Clipboard.FindFormatID('Biff8');
If cfBiff8Format = 0 Then
cfBiff8Format := RegisterClipboardFormat('Biff8');
// Ensure that the 'Biff5' clipboard format is registered
cfBiff5Format := Clipboard.FindFormatID('Biff5');
If cfBiff5Format = 0 Then
cfBiff5Format := RegisterClipboardFormat('Biff5');
stream := TMemoryStream.Create;
try
// At first write BIFF8 format
FWorkbook.CopyToClipboardStream(stream, sfExcel8);
Clipboard.AddFormat(cfBiff8Format, stream);
(stream as TMemoryStream).Clear;
// Then write BIFF5 format
FWorkbook.CopyToClipboardStream(stream, sfExcel5);
Clipboard.AddFormat(cfBiff5Format, stream);
// To do: HTML format, CSV format, XML format
// I don't know which format is written by xlsx and ods natively.
finally
stream.Free;
end;
finally
Clipboard.Close;
end;
FCutPending := false;
ClearCellClipboard;

View File

@ -141,13 +141,16 @@ type
ReaderClass: TsSpreadReaderClass;
WriterClass: TsSpreadWriterClass;
Format: TsSpreadsheetFormat;
CanReadFromClipboard: Boolean;
CanWriteToClipboard: Boolean;
end;
var
GsSpreadFormats: array of TsSpreadFormatData;
procedure RegisterSpreadFormat(AReaderClass: TsSpreadReaderClass;
AWriterClass: TsSpreadWriterClass; AFormat: TsSpreadsheetFormat);
AWriterClass: TsSpreadWriterClass; AFormat: TsSpreadsheetFormat;
ACanReadFromClipboard: Boolean = false; ACanWriteToClipboard: Boolean = false);
implementation
@ -162,7 +165,9 @@ uses
procedure RegisterSpreadFormat(
AReaderClass: TsSpreadReaderClass;
AWriterClass: TsSpreadWriterClass;
AFormat: TsSpreadsheetFormat);
AFormat: TsSpreadsheetFormat;
ACanReadFromClipboard: Boolean = false;
ACanWriteToClipboard: Boolean = false);
var
len: Integer;
begin
@ -172,6 +177,8 @@ begin
GsSpreadFormats[len].ReaderClass := AReaderClass;
GsSpreadFormats[len].WriterClass := AWriterClass;
GsSpreadFormats[len].Format := AFormat;
GsSpreadFormats[len].CanReadFromClipboard := ACanReadFromClipboard;
GsSpreadFormats[len].CanWriteToClipboard := ACanWriteToClipboard;
end;

View File

@ -1807,7 +1807,7 @@ initialization
Excel5Settings.CodePage := GetDefaultTextEncoding;
{$ENDIF}
RegisterSpreadFormat(TsSpreadBIFF5Reader, TsSpreadBIFF5Writer, sfExcel5);
RegisterSpreadFormat(TsSpreadBIFF5Reader, TsSpreadBIFF5Writer, sfExcel5, false, true);
MakeLEPalette(PALETTE_BIFF5);
end.

View File

@ -3443,7 +3443,7 @@ end;
initialization
// Registers this reader / writer in fpSpreadsheet
RegisterSpreadFormat(TsSpreadBIFF8Reader, TsSpreadBIFF8Writer, sfExcel8);
RegisterSpreadFormat(TsSpreadBIFF8Reader, TsSpreadBIFF8Writer, sfExcel8, false, true);
// Converts the palette to litte-endian
MakeLEPalette(PALETTE_BIFF8);

View File

@ -463,6 +463,8 @@ type
FCodePage: String; // in a format prepared for lconvencoding.ConvertEncoding
FFirstNumFormatIndexInFile: Integer;
FPalette: TsPalette;
FClipboardMode: Boolean;
procedure AddBuiltinNumFormats; override;
function FindXFIndex(ACell: PCell): Integer; virtual;
function FixLineEnding(const AText: String): String;
@ -571,6 +573,7 @@ type
constructor Create(AWorkbook: TsWorkbook); override;
destructor Destroy; override;
procedure CheckLimitations; override;
procedure WriteToClipboardStream(AStream: TStream); override;
end;
procedure AddBuiltinBiffFormats(AList: TStringList;
@ -3945,6 +3948,10 @@ begin
AStream.WriteWord(WordToLE(w));
end;
procedure TsSpreadBIFFWriter.WriteToClipboardStream(AStream: TStream);
begin
WriteToStream(AStream);
end;
procedure TsSpreadBIFFWriter.WriteVirtualCells(AStream: TStream);
var