From 590c9d8a471953e722af77ed108335f09577d9e8 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Tue, 26 Jan 2016 23:37:08 +0000 Subject: [PATCH] fpspreadsheet: More combinations of source and destination cells for copy/paste to clipboard. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4477 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/fpspreadsheet/fpspreadsheet.pas | 185 ++++++++++-------- .../fpspreadsheet/fpspreadsheetgrid.pas | 14 +- components/fpspreadsheet/fpsutils.pas | 4 +- 3 files changed, 119 insertions(+), 84 deletions(-) diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 9c8030a99..eb80e0749 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -748,27 +748,7 @@ type procedure PasteFromClipboardStream(AStream: TStream; AFormat: TsSpreadsheetFormat; AOperation: TsCopyOperation; AParams: TsStreamParams = []; ATransposed: Boolean = false); - (* - { Color handling } - function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String; - function GetColorName(AColorIndex: TsColor): string; overload; - procedure GetColorName(AColorValue: TsColorValue; out AName: String); overload; - function GetPaletteColor(AColorIndex: TsColor): TsColorValue; - function GetPaletteColorAsHTMLStr(AColorIndex: TsColor): String; - procedure SetPaletteColor(AColorIndex: TsColor; AColorValue: TsColorValue); - function GetPaletteSize: Integer; - procedure UseDefaultPalette; - procedure UsePalette(APalette: PsPalette; APaletteCount: Word; - ABigEndian: Boolean = false); - function UsesColor(AColorIndex: TsColor): Boolean; - *) - (* - { Searching } - function SearchFirst(ASearchText: String; AParams: TsSearchParams; - out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean; - function SearchNext(out AWorksheet: TsWorksheet; - out ARow, ACol: Cardinal): Boolean; - *) + { Utilities } procedure DisableNotifications; procedure EnableNotifications; @@ -1654,18 +1634,18 @@ begin CopyFormat(AFromCell, AToCell); // Merged? - if IsMergeBase(AFromCell) then + if srcSheet.IsMergeBase(AFromCell) then begin - FindMergedRange(AFromCell, row1, col1, row2, col2); + srcSheet.FindMergedRange(AFromCell, row1, col1, row2, col2); MergeCells(toRow, toCol, toRow + LongInt(row2) - LongInt(row1), toCol + LongInt(col2) - LongInt(col1)); end; // Copy comment - if HasComment(AFromCell) then + if srcSheet.HasComment(AFromCell) then WriteComment(AToCell, ReadComment(AFromCell)); // Copy hyperlink - hyperlink := FindHyperlink(AFromCell); + hyperlink := srcSheet.FindHyperlink(AFromCell); if hyperlink <> nil then WriteHyperlink(AToCell, hyperlink^.Target, hyperlink^.Tooltip); @@ -6515,37 +6495,6 @@ begin Unused(arg); TsWorksheet(data).Free; end; - (* -{@@ ---------------------------------------------------------------------------- - Searches the first cell matching the ASearchText according to the - specified AParams. - Use SearchNext for subsequent calls for the next occurances. - The function result is TRUE if the search text has been found. In this case - AWorksheet, ARow and ACol specify the cell containing the search text. --------------------------------------------------------------------------------} -function TsWorkbook.SearchFirst(ASearchText: String; AParams: TsSearchParams; - out AWorksheet: TsWorksheet; out ARow, ACol: Cardinal): Boolean; -begin - FreeAndNil(FSearchEngine); - FSearchEngine := TsSearchEngine.Create(self); - with (FSearchEngine as TsSearchEngine) do - Result := FindFirst(ASearchText, AParams, AWorksheet, ARow, ACol); -end; - -{@@ ---------------------------------------------------------------------------- - Searches the next cell matching the text and params specified a the preceding - call to SearchFirst. - The function result is TRUE if the search text has been found. In this case - AWorksheet, ARow and ACol specify the cell containing the search text. --------------------------------------------------------------------------------} -function TsWorkbook.SearchNext(out AWorksheet: TsWorksheet; - out ARow, ACol: Cardinal): Boolean; -begin - if FSearchEngine = nil then - Result := false else - Result := (FSearchEngine as TsSearchEngine).FindNext(AWorksheet, ARow, ACol); -end; - *) {@@ ---------------------------------------------------------------------------- Helper method to disable notification of visual controls @@ -7931,6 +7880,8 @@ begin for c := sel.Col1 to sel.Col2 do begin srccell := ActiveWorksheet.FindCell(r, c); + if ActiveWorksheet.IsMerged(srccell) then + srccell := ActiveWorksheet.FindMergeBase(srccell); if srccell <> nil then begin destcell := clipsheet.AddCell(r, c); clipsheet.CopyCell(srccell, destcell); @@ -7970,7 +7921,10 @@ var r, c: LongInt; dr, dc: LongInt; srcCell, destCell: PCell; - i, n: Integer; + i: Integer; // counter + ncs, nrs, ncd, nrd: Integer; // Num cols source, num rows source, ... + rdest, cdest: Integer; // row and column index at destination + nselS, nselD: Integer; // count of selected blocks begin if AStream = nil then exit; @@ -7990,29 +7944,40 @@ begin // treatment for clipboard, if needed. clipbook.ReadFromStream(AStream, AFormat, AParams + [spClipboard]); 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); - case AOperation of - coCopyCell : ActiveWorksheet.CopyCell(srcCell, destCell); - coCopyValue : ActiveWorksheet.CopyValue(srcCell, destCell); - coCopyFormat : ActiveWorksheet.CopyFormat(srcCell, destCell); - coCopyFormula : ActiveWorksheet.CopyFormula(srcCell, destCell); - end; - end; - // Select the same cells as in the clipboard - n := clipsheet.GetSelectionCount; - if n > 0 then + + // count of blocks in source (clipboard sheet) + nselS := clipsheet.GetSelectionCount; + // count of selected blocks at destination + nselD := ActiveWorksheet.GetSelectionCount; + + // ------------------------------------------------------------------------- + // Case (1): Destination is a single cell, source can be any shape + // --> Source shape is duplicated starting at destination + // ------------------------------------------------------------------------- + if (nselD = 1) + and (ActiveWorksheet.GetSelection[0].Col1 = ActiveWorksheet.GetSelection[0].Col2) + and (ActiveWorksheet.GetSelection[0].Row1 = ActiveWorksheet.GetSelection[0].Row2) + then begin + // Find offset of active cell to left/top cell in clipboard sheet + dr := LongInt(ActiveWorksheet.ActiveCellRow) - clipsheet.GetFirstRowIndex(true); + dc := LongInt(ActiveWorksheet.ActiveCellCol) - clipsheet.GetFirstColIndex(true); + // Copy cells from clipboard sheet to active worksheet + // Shift them such that top/left of clipboard sheet is at active cell + for srcCell in clipsheet.Cells do begin - SetLength(selArray, n); - for i := 0 to n-1 do + r := LongInt(srcCell^.Row) + dr; + c := LongInt(srcCell^.Col) + dc; + destcell := ActiveWorksheet.GetCell(r, c); + case AOperation of + coCopyCell : ActiveWorksheet.CopyCell(srcCell, destCell); + coCopyValue : ActiveWorksheet.CopyValue(srcCell, destCell); + coCopyFormat : ActiveWorksheet.CopyFormat(srcCell, destCell); + coCopyFormula : ActiveWorksheet.CopyFormula(srcCell, destCell); + end; + end; + // Select all copied cells + SetLength(selArray, nselS); + for i := 0 to nselS-1 do begin sel := clipsheet.GetSelection[i]; selArray[i].Row1 := LongInt(sel.Row1) + dr; @@ -8032,7 +7997,67 @@ begin c := sel.Col2; end; ActiveWorksheet.SelectCell(r + dr, c + dc); - end; + end + else + // ------------------------------------------------------------------------- + // Case (2): Source is a single block (not necessarily a cell), Dest can be + // any shape --> source is tiled into destination + // ------------------------------------------------------------------------- + if nselS = 1 then + begin + // size of source block + with clipsheet do + begin + ncs := LongInt(GetLastColIndex(true)) - LongInt(GetFirstColIndex(true)) + 1; + nrs := LongInt(GetLastRowIndex(true)) - LongInt(GetFirstRowIndex(true)) + 1; + end; + // Iterate over all destination blocks + for i := 0 to nselD-1 do + begin + // size of current selected block at destination + with ActiveWorksheet.GetSelection[i] do + begin + ncd := LongInt(Col2) - LongInt(Col1) + 1; + nrd := LongInt(Row2) - LongInt(Row1) + 1; + end; + r := ActiveWorksheet.GetSelection[i].Row1; + while r <= ActiveWorksheet.GetSelection[i].Row2 do begin + c := ActiveWorksheet.GetSelection[i].Col1; + while c <= ActiveWorksheet.GetSelection[i].Col2 do begin + dr := r - clipsheet.GetFirstRowIndex; + dc := c - clipsheet.GetFirstColIndex; + for srccell in clipsheet.Cells do + begin + rdest := srccell^.Row + dr; + if rdest > ActiveWorksheet.GetSelection[i].Row2 then + Continue; + cdest := srcCell^.Col + dc; + if cdest > ActiveWorksheet.GetSelection[i].Col2 then + Continue; + destcell := ActiveWorksheet.GetCell( + LongInt(srcCell^.Row) + dr, + LongInt(srcCell^.Col) + dc + ); + case AOperation of + coCopyCell : ActiveWorksheet.CopyCell(srcCell, destCell); + coCopyValue : ActiveWorksheet.CopyValue(srcCell, destCell); + coCopyFormat : ActiveWorksheet.CopyFormat(srcCell, destCell); + coCopyFormula : ActiveWorksheet.CopyFormula(srcCell, destCell); + end; + end; // for srcCell + inc(c, ncs); + end; // while c... + inc(r, nrs); + end; // while r... + end; // for i + // No need to select copied cells - they already are. + end + else + // ------------------------------------------------------------------------- + // Other arrangements of source and destination are not supported + // ------------------------------------------------------------------------- + raise Exception.Create('This arrangement of source and destination '+ + 'cells in not supported for copy & paste'); finally clipbook.Free; end; diff --git a/components/fpspreadsheet/fpspreadsheetgrid.pas b/components/fpspreadsheet/fpspreadsheetgrid.pas index 83e6a0b97..87d4aa5eb 100644 --- a/components/fpspreadsheet/fpspreadsheetgrid.pas +++ b/components/fpspreadsheet/fpspreadsheetgrid.pas @@ -1526,14 +1526,16 @@ end; procedure TsCustomWorksheetGrid.DoCutToClipboard; begin + // This next comment does not seem to be valid any more: Issue handled by eating key in KeyDown // Remove for the moment: If TsCopyActions is available this code would be executed twice (and destroy the clipboard) - //WorkbookSource.CutCellsToClipboard; + WorkbookSource.CutCellsToClipboard; end; procedure TsCustomWorksheetGrid.DoPasteFromClipboard; begin + // This next comment does not seem to be valid any more: Issue handled by eating key in KeyDown // Remove for the moment: If TsPasteActions is available this code would be executed twice - //WorkbookSource.PasteCellsFromClipboard(coCopyCell); + WorkbookSource.PasteCellsFromClipboard(coCopyCell); end; { Make the cell editor the same size as the edited cell, in particular for @@ -2347,6 +2349,7 @@ var cell: PCell; r1,c1,r2,c2: Cardinal; delta: Integer; + savedPenMode: TPenMode; begin if Worksheet = nil then exit; @@ -2382,6 +2385,7 @@ begin end; } // Set up the canvas + savedPenMode := Canvas.Pen.Mode; Canvas.Pen.Assign(FSelPen); if UseXORFeatures then begin Canvas.Pen.Color := clWhite; @@ -2391,6 +2395,8 @@ begin // Paint Canvas.Rectangle(R); + + Canvas.Pen.Mode := savedPenMode; end; {@@ ---------------------------------------------------------------------------- @@ -3830,6 +3836,10 @@ begin end; inherited; + + case Key of + VK_C, VK_X, VK_V: Key := 0; // Clipboard has already been handled, avoid passing key to CellAction + end; end; {@@ ---------------------------------------------------------------------------- diff --git a/components/fpspreadsheet/fpsutils.pas b/components/fpspreadsheet/fpsutils.pas index 8a901e444..9a0165255 100644 --- a/components/fpspreadsheet/fpsutils.pas +++ b/components/fpspreadsheet/fpsutils.pas @@ -2238,7 +2238,7 @@ begin (AFont.Color = AColor) and (AFont.Position = APos); end; - + (* {@@ ---------------------------------------------------------------------------- Constructs a string of length "Len" containing random uppercase characters -------------------------------------------------------------------------------} @@ -2248,7 +2248,7 @@ begin While Length(Result) < Len do Result := Result + char(ord('A') + random(26)); end; - (* + {@@ ---------------------------------------------------------------------------- Constructs a unique folder name in the temp directory of the OS -------------------------------------------------------------------------------}