You've already forked lazarus-ccr
fpspreadsheet: Add "Paste from clipboard" (for biff8 format)
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4355 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -655,18 +655,22 @@ type
|
||||
out SheetType: TsSpreadsheetFormat): Boolean; overload;
|
||||
class function GetFormatFromFileHeader(AStream: TStream;
|
||||
out SheetType: TsSpreadsheetFormat): Boolean; overload;
|
||||
function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsBasicSpreadReader;
|
||||
function CreateSpreadReader(AFormat: TsSpreadsheetFormat;
|
||||
AClipboardMode: Boolean = false): TsBasicSpreadReader;
|
||||
function CreateSpreadWriter(AFormat: TsSpreadsheetFormat;
|
||||
AClipboardMode: Boolean = false): TsBasicSpreadWriter;
|
||||
procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat); overload;
|
||||
procedure ReadFromFile(AFileName: string); overload;
|
||||
procedure ReadFromFileIgnoringExtension(AFileName: string);
|
||||
procedure ReadFromStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
||||
procedure ReadFromStream(AStream: TStream; AFormat: TsSpreadsheetFormat;
|
||||
AClipboardMode: Boolean = false);
|
||||
procedure WriteToFile(const AFileName: string;
|
||||
const AFormat: TsSpreadsheetFormat;
|
||||
const AOverwriteExisting: Boolean = False); overload;
|
||||
procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False); overload;
|
||||
procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat; AClipboardMode: Boolean = false);
|
||||
procedure WriteToFile(const AFileName: String;
|
||||
const AOverwriteExisting: Boolean = False); overload;
|
||||
procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat;
|
||||
AClipboardMode: Boolean = false);
|
||||
|
||||
{ Worksheet list handling methods }
|
||||
function AddWorksheet(AName: string;
|
||||
@ -727,6 +731,7 @@ type
|
||||
|
||||
{ Clipboard }
|
||||
procedure CopyToClipboardStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
||||
procedure PasteFromClipboardStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
||||
(*
|
||||
{ Color handling }
|
||||
function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String;
|
||||
@ -1594,10 +1599,10 @@ begin
|
||||
toRow := AToCell^.Row;
|
||||
toCol := AToCell^.Col;
|
||||
|
||||
// Copy cell values and formats
|
||||
// Copy cell values
|
||||
AToCell^ := AFromCell^;
|
||||
|
||||
// Fix row and column indexes overwritten
|
||||
// Restore row and column indexes overwritten by the previous instruction
|
||||
AToCell^.Row := toRow;
|
||||
AToCell^.Col := toCol;
|
||||
AToCell^.Worksheet := self;
|
||||
@ -3558,12 +3563,9 @@ end;
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorksheet.SelectCell(ARow, ACol: Cardinal);
|
||||
begin
|
||||
if not FWorkbook.NotificationsEnabled then
|
||||
exit;
|
||||
|
||||
FActiveCellRow := ARow;
|
||||
FActiveCellCol := ACol;
|
||||
if Assigned(FOnSelectCell) then
|
||||
if FWorkbook.NotificationsEnabled and Assigned(FOnSelectCell) then
|
||||
FOnSelectCell(Self, ARow, ACol);
|
||||
end;
|
||||
|
||||
@ -6603,17 +6605,22 @@ end;
|
||||
to workbook. An exception is raised when the document has
|
||||
a different format.
|
||||
|
||||
@param AClipboardMode If TRUE it is checked that the reader class supports
|
||||
clipboard access.
|
||||
|
||||
@return An instance of a TsCustomSpreadReader descendent which is able to
|
||||
read the given file format.
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsWorkbook.CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsBasicSpreadReader;
|
||||
function TsWorkbook.CreateSpreadReader(AFormat: TsSpreadsheetFormat;
|
||||
AClipboardMode: Boolean = false): TsBasicSpreadReader;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Result := nil;
|
||||
|
||||
for i := 0 to Length(GsSpreadFormats) - 1 do
|
||||
if GsSpreadFormats[i].Format = AFormat then
|
||||
for i := 0 to High(GsSpreadFormats) do
|
||||
if (GsSpreadFormats[i].Format = AFormat) and
|
||||
((not AClipboardMode) or GsSpreadformats[i].CanReadFromClipboard) then
|
||||
begin
|
||||
Result := GsSpreadFormats[i].ReaderClass.Create(self);
|
||||
Break;
|
||||
@ -6641,9 +6648,9 @@ var
|
||||
begin
|
||||
Result := nil;
|
||||
|
||||
for i := 0 to Length(GsSpreadFormats) - 1 do
|
||||
for i := 0 to High(GsSpreadFormats) do
|
||||
if (GsSpreadFormats[i].Format = AFormat) and
|
||||
(AClipboardMode or GsSpreadFormats[i].CanWriteToClipboard) then
|
||||
((not AClipboardMode) or GsSpreadFormats[i].CanWriteToClipboard) then
|
||||
begin
|
||||
Result := GsSpreadFormats[i].WriterClass.Create(self);
|
||||
Break;
|
||||
@ -6807,9 +6814,10 @@ end;
|
||||
|
||||
@param AStream Stream being read
|
||||
@param AFormat File format assumed.
|
||||
@param AClipboardMode The calling method has read the stream from the clipboard.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorkbook.ReadFromStream(AStream: TStream;
|
||||
AFormat: TsSpreadsheetFormat);
|
||||
AFormat: TsSpreadsheetFormat; AClipboardMode: Boolean = false);
|
||||
var
|
||||
AReader: TsBasicSpreadReader;
|
||||
ok: Boolean;
|
||||
@ -6821,6 +6829,8 @@ begin
|
||||
try
|
||||
ok := false;
|
||||
AStream.Position := 0;
|
||||
if AClipboardMode then
|
||||
AReader.ReadFromClipboardStream(AStream) else
|
||||
AReader.ReadFromStream(AStream);
|
||||
ok := true;
|
||||
finally
|
||||
@ -6970,6 +6980,10 @@ begin
|
||||
// name here as well.
|
||||
if (FLockCount = 0) and Assigned(FOnAddWorksheet) then
|
||||
FOnAddWorksheet(self, Result);
|
||||
|
||||
// Make sure that there is an "active" worksheet
|
||||
if FActiveWorksheet = nil then
|
||||
SelectWorksheet(result);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
@ -7775,7 +7789,7 @@ begin
|
||||
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.
|
||||
// to TRUE to use the dedicated clipboard routine if needed.
|
||||
clipbook.WriteToStream(AStream, AFormat, true);
|
||||
|
||||
// The calling routine which copies the stream to the clipboard requires
|
||||
@ -7786,6 +7800,79 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Copies the cells stored in the specified stream to the active worksheet.
|
||||
The provided stream contains data from the system's clipboard.
|
||||
Note that transfer from the clipboard to the stream has to be done by the
|
||||
calling routine since fpspreadsheet does not "know" the system's clipboard.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorkbook.PasteFromClipboardStream(AStream: TStream;
|
||||
AFormat: TsSpreadsheetFormat);
|
||||
var
|
||||
clipbook: TsWorkbook;
|
||||
clipsheet: TsWorksheet;
|
||||
sel: TsCellRange;
|
||||
selArray: TsCellRangeArray;
|
||||
r, c: LongInt;
|
||||
dr, dc: LongInt;
|
||||
srccell, destcell: PCell;
|
||||
i, n: Integer;
|
||||
begin
|
||||
if AStream = nil then
|
||||
exit;
|
||||
|
||||
if ActiveWorksheet = nil then
|
||||
exit;
|
||||
|
||||
// Create workbook into which the clipboard stream will write
|
||||
clipbook := TsWorkbook.Create;
|
||||
try
|
||||
clipbook.Options := clipbook.Options + [boReadFormulas];
|
||||
// Read stream into this temporary workbook
|
||||
// Set last parameter (ClipboardMode) to TRUE to activate special format
|
||||
// treatment for clipboard, if needed.
|
||||
clipbook.ReadFromStream(AStream, AFormat, true);
|
||||
clipsheet := clipbook.GetWorksheetByIndex(0);
|
||||
// Find offset of active cell to left/top cell in temporary sheet
|
||||
dr := LongInt(ActiveWorksheet.ActiveCellRow) - clipsheet.GetFirstRowIndex(true);
|
||||
dc := LongInt(ActiveWorksheet.ActiveCellCol) - clipsheet.GetFirstColIndex(true);
|
||||
// Copy cells from temporary workbook to active worksheet.
|
||||
// Shift them such that the top/left cell of temp sheet is at the active cell.
|
||||
for srccell in clipsheet.Cells do
|
||||
begin
|
||||
r := LongInt(srcCell.Row) + dr;
|
||||
c := LongInt(srcCell.Col) + dc;
|
||||
destcell := ActiveWorksheet.GetCell(r, c);
|
||||
ActiveWorksheet.CopyCell(srccell, destcell);
|
||||
end;
|
||||
// Select the same cells as in the clipboard
|
||||
n := clipsheet.GetSelectionCount;
|
||||
SetLength(selArray, n);
|
||||
for i := 0 to n-1 do
|
||||
begin
|
||||
sel := clipsheet.GetSelection[i];
|
||||
selArray[i].Row1 := sel.Row1 + dr;
|
||||
selArray[i].Col1 := sel.Col1 + dc;
|
||||
selArray[i].Row2 := sel.Row2 + dr;
|
||||
selArray[i].Col2 := sel.Col2 + dc;
|
||||
end;
|
||||
ActiveWorksheet.SetSelection(selArray);
|
||||
// Select active cell. If not found in the file, let's use the last cell of the selections
|
||||
if (clipsheet.ActiveCellRow <> 0) and (clipsheet.ActiveCellCol <> 0) then
|
||||
begin
|
||||
r := clipsheet.ActiveCellRow;
|
||||
c := clipsheet.ActiveCellCol;
|
||||
end else
|
||||
begin
|
||||
r := sel.Row2;
|
||||
c := sel.Col2;
|
||||
end;
|
||||
ActiveWorksheet.SelectCell(r + dr, c + dc);
|
||||
finally
|
||||
clipbook.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
(*
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Adds a color to the palette and returns its palette index, but only if the
|
||||
|
@ -1151,11 +1151,15 @@ var
|
||||
cell: PCell;
|
||||
stream: TStream;
|
||||
begin
|
||||
sel := FWorksheet.GetSelection;
|
||||
if Length(sel) = 0 then
|
||||
exit;
|
||||
|
||||
Clipboard.Open;
|
||||
try
|
||||
Clipboard.Clear;
|
||||
|
||||
// Ensure the 'Biff8' clipboard format is registered
|
||||
// Ensure that the 'Biff8' clipboard format is registered
|
||||
cfBiff8Format := Clipboard.FindFormatID('Biff8');
|
||||
If cfBiff8Format = 0 Then
|
||||
cfBiff8Format := RegisterClipboardFormat('Biff8');
|
||||
@ -1189,9 +1193,6 @@ begin
|
||||
FCutPending := false;
|
||||
|
||||
ClearCellClipboard;
|
||||
sel := FWorksheet.GetSelection;
|
||||
if Length(sel) = 0 then
|
||||
exit;
|
||||
|
||||
for i:=0 to High(sel) do
|
||||
for r := sel[i].Row1 to sel[i].Row2 do
|
||||
@ -1232,7 +1233,51 @@ var
|
||||
cell: PCell;
|
||||
baserng, rng: TsCellRange;
|
||||
baseRow, baseCol: Cardinal;
|
||||
cf: Integer;
|
||||
fmt: TsSpreadsheetFormat;
|
||||
stream: TStream;
|
||||
begin
|
||||
Clipboard.Open;
|
||||
try
|
||||
// Ensure that the 'Biff8' clipboard format is registered
|
||||
// In fpspreadsheet, this is currently the clipboard format which supports most features.
|
||||
fmt := sfExcel8;
|
||||
cf := Clipboard.FindFormatID('Biff8');
|
||||
If cf = 0 Then
|
||||
cf := RegisterClipboardFormat('Biff8');
|
||||
|
||||
// If Biff8 cannot be found use Biff5 instead
|
||||
if cf = 0 then
|
||||
begin
|
||||
fmt := sfExcel5;
|
||||
cf := Clipboard.FindFormatID('Biff5');
|
||||
If cf = 0 Then
|
||||
cf := RegisterClipboardFormat('Biff5');
|
||||
end;
|
||||
|
||||
// Exit if there are no spreadsheet data in clipboard
|
||||
if cf = 0 then
|
||||
MessageDlg('No appropriate spreadsheet data in clipboard', mtError, [mbOk], 0);
|
||||
|
||||
stream := TMemoryStream.Create;
|
||||
try
|
||||
Clipboard.GetFormat(cf, stream);
|
||||
FWorkbook.PasteFromClipboardStream(stream, fmt);
|
||||
|
||||
// To do: HTML format, CSV format, XML format, TEXT format
|
||||
// I don't know which format is written by xlsx and ods natively.
|
||||
finally
|
||||
stream.Free;
|
||||
end;
|
||||
finally
|
||||
Clipboard.Close;
|
||||
end;
|
||||
|
||||
exit;
|
||||
|
||||
|
||||
|
||||
|
||||
if CellClipboard.Count = 0 then
|
||||
exit;
|
||||
|
||||
|
@ -3443,7 +3443,7 @@ end;
|
||||
initialization
|
||||
|
||||
// Registers this reader / writer in fpSpreadsheet
|
||||
RegisterSpreadFormat(TsSpreadBIFF8Reader, TsSpreadBIFF8Writer, sfExcel8, false, true);
|
||||
RegisterSpreadFormat(TsSpreadBIFF8Reader, TsSpreadBIFF8Writer, sfExcel8, true, true);
|
||||
|
||||
// Converts the palette to litte-endian
|
||||
MakeLEPalette(PALETTE_BIFF8);
|
||||
|
@ -357,6 +357,7 @@ type
|
||||
FPalette: TsPalette;
|
||||
FWorksheetNames: TStrings;
|
||||
FCurrentWorksheet: Integer;
|
||||
FActivePane: Integer;
|
||||
|
||||
procedure AddBuiltinNumFormats; override;
|
||||
procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual;
|
||||
@ -452,6 +453,7 @@ type
|
||||
public
|
||||
constructor Create(AWorkbook: TsWorkbook); override;
|
||||
destructor Destroy; override;
|
||||
procedure ReadFromClipboardStream(AStream: TStream); override;
|
||||
end;
|
||||
|
||||
|
||||
@ -463,7 +465,6 @@ 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;
|
||||
@ -823,6 +824,9 @@ begin
|
||||
// Initial base date in case it won't be read from file
|
||||
FDateMode := dm1900;
|
||||
|
||||
// Index of active pane (no panes --> index is 3 ... OMG!...)
|
||||
FActivePane := 3;
|
||||
|
||||
// Limitations of BIFF5 and BIFF8 file format
|
||||
FLimitations.MaxColCount := 256;
|
||||
FLimitations.MaxRowCount := 65536;
|
||||
@ -1332,6 +1336,16 @@ begin
|
||||
FWorksheet.DefaultRowHeight := h - ROW_HEIGHT_CORRECTION;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Public specialized stream reading method for clipboard access.
|
||||
For BIFF file format, data are stored in the clipboard in the same way as in
|
||||
a regular stream/file.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsSpreadBIFFReader.ReadFromClipboardStream(AStream: TStream);
|
||||
begin
|
||||
ReadFromStream(AStream);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads the (number) FORMAT record for formatting numerical data
|
||||
To be overridden by descendants.
|
||||
@ -1723,12 +1737,16 @@ begin
|
||||
if (FWorksheet.LeftPaneWidth = 0) and (FWorksheet.TopPaneHeight = 0) then
|
||||
FWorksheet.Options := FWorksheet.Options - [soHasFrozenPanes];
|
||||
|
||||
{ There's more information which is not supported here:
|
||||
Offset Size Description
|
||||
4 2 Index to first visible row in bottom pane(s)
|
||||
6 2 Index to first visible column in right pane(s)
|
||||
8 1 Identifier of pane with active cell cursor (see below)
|
||||
[9] 1 Not used (BIFF5-BIFF8 only, not written in BIFF2-BIFF4) }
|
||||
// Index to first visible row in bottom pane(s) -- not used
|
||||
AStream.ReadWord;
|
||||
|
||||
// Index to first visible column in right pane(s) -- not used
|
||||
AStream.ReadWord;
|
||||
|
||||
// Identifier of pane with active cell cursor
|
||||
FActivePane := AStream.ReadByte;
|
||||
|
||||
// If BIFF5-BIFF8 there is 1 more byte which is not used here.
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
@ -2175,12 +2193,14 @@ end;
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsSpreadBIFFReader.ReadSELECTION(AStream: TStream);
|
||||
var
|
||||
{%H-}actPane: byte;
|
||||
{%H-}paneIdx: byte;
|
||||
{%H-}rngIndex: Word;
|
||||
actRow, actCol: Word;
|
||||
n, i: Integer;
|
||||
sel: TsCellRangeArray;
|
||||
begin
|
||||
// Active pane
|
||||
actPane := AStream.ReadByte;
|
||||
// Pane index
|
||||
paneIdx := AStream.ReadByte;
|
||||
|
||||
// Row index of the active cell
|
||||
actRow := WordLEToN(AStream.ReadWord);
|
||||
@ -2192,10 +2212,25 @@ begin
|
||||
rngIndex := WordLEToN(AStream.ReadWord);
|
||||
|
||||
// Count of selected ranges
|
||||
// Selected ranges --> ignore
|
||||
n := WordLEToN(AStream.ReadWord);
|
||||
SetLength(sel, n);
|
||||
|
||||
// Selected ranges
|
||||
for i := 0 to n - 1 do
|
||||
begin
|
||||
sel[i].Row1 := WordLEToN(AStream.ReadWord);
|
||||
sel[i].Row2 := WordLEToN(AStream.ReadWord);
|
||||
sel[i].Col1 := AStream.ReadByte; // 8-bit column indexes even for biff8!
|
||||
sel[i].Col2 := AStream.ReadByte;
|
||||
end;
|
||||
|
||||
// Apply selections to worksheet, but only in the pane with the cursor
|
||||
if paneIdx = FActivePane then
|
||||
begin
|
||||
if Length(sel) > 0 then FWorksheet.SetSelection(sel);
|
||||
FWorksheet.SelectCell(actRow, actCol);
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Reads a SHAREDFMLA record, i.e. reads cell range coordinates and a rpn
|
||||
@ -3126,6 +3161,13 @@ end;
|
||||
Writes a PANE record to the stream.
|
||||
Valid for all BIFF versions. The difference for BIFF5-BIFF8 is a non-used
|
||||
byte at the end. Activate IsBiff58 in these cases.
|
||||
|
||||
Pane numbering scheme: <pre>
|
||||
--------- ----------- ----------- -----------
|
||||
| | | 3 | | | | | 3 | 1 |
|
||||
| 3 | |----------- | 3 | 1 | |-----+-----
|
||||
| | | 2 | | | | | 2 | 0 |
|
||||
--------- ---------- ----------- ----------- </pre>
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsSpreadBIFFWriter.WritePane(AStream: TStream; ASheet: TsWorksheet;
|
||||
IsBiff58: Boolean; out ActivePane: Byte);
|
||||
@ -3170,11 +3212,7 @@ begin
|
||||
else
|
||||
AStream.WriteWord(WordToLE(0));
|
||||
|
||||
{ Identifier of pane with active cell cursor
|
||||
0 = right-bottom
|
||||
1 = right-top
|
||||
2 = left-bottom
|
||||
3 = left-top }
|
||||
{ Identifier of pane with active cell cursor, see header for numbering scheme }
|
||||
if (soHasFrozenPanes in ASheet.Options) then begin
|
||||
if (ASheet.LeftPaneWidth = 0) and (ASheet.TopPaneHeight = 0) then
|
||||
ActivePane := 3
|
||||
|
Reference in New Issue
Block a user