From 98e1c88c1e894ac2a6174483df1ea483d561f6be Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Wed, 17 Dec 2014 23:28:41 +0000 Subject: [PATCH] fpspreadsheet: Initial implementation of a simple clipboard (within appliation only) for TsWorksheetGrid. Not yet fully working. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3843 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../fpspreadsheet/examples/fpsctrls/main.lfm | 310 +++++++++++++++--- .../fpspreadsheet/examples/fpsctrls/main.pas | 25 +- components/fpspreadsheet/fpsactions.pas | 40 ++- components/fpspreadsheet/fpspreadsheet.pas | 59 +++- .../fpspreadsheet/fpspreadsheetctrls.pas | 260 ++++++++++++++- 5 files changed, 618 insertions(+), 76 deletions(-) diff --git a/components/fpspreadsheet/examples/fpsctrls/main.lfm b/components/fpspreadsheet/examples/fpsctrls/main.lfm index 9f56cd97d..63783260c 100644 --- a/components/fpspreadsheet/examples/fpsctrls/main.lfm +++ b/components/fpspreadsheet/examples/fpsctrls/main.lfm @@ -159,31 +159,23 @@ object Form1: TForm1 EdgeBorders = [] Images = ImageList TabOrder = 3 - object ToolButton4: TToolButton - Left = 232 - Height = 26 - Top = 0 - Width = 3 - Caption = 'ToolButton4' - Style = tbsDivider - end object ToolButton6: TToolButton - Left = 283 + Left = 280 Top = 0 Action = AcFontBold end object ToolButton7: TToolButton - Left = 307 + Left = 304 Top = 0 Action = AcFontItalic end object ToolButton8: TToolButton - Left = 331 + Left = 328 Top = 0 Action = AcFontUnderline end object ToolButton10: TToolButton - Left = 379 + Left = 376 Height = 26 Top = 0 Width = 5 @@ -191,27 +183,27 @@ object Form1: TForm1 Style = tbsDivider end object ToolButton11: TToolButton - Left = 355 + Left = 352 Top = 0 Action = AcFontStrikeout end object ToolButton12: TToolButton - Left = 384 + Left = 381 Top = 0 Action = AcHorAlignLeft end object ToolButton13: TToolButton - Left = 408 + Left = 405 Top = 0 Action = AcHorAlignCenter end object ToolButton14: TToolButton - Left = 432 + Left = 429 Top = 0 Action = AcHorAlignRight end object ToolButton15: TToolButton - Left = 456 + Left = 453 Height = 26 Top = 0 Width = 5 @@ -219,22 +211,22 @@ object Form1: TForm1 Style = tbsDivider end object ToolButton16: TToolButton - Left = 461 + Left = 458 Top = 0 Action = AcVertAlignTop end object ToolButton17: TToolButton - Left = 485 + Left = 482 Top = 0 Action = AcVertAlignCenter end object ToolButton18: TToolButton - Left = 509 + Left = 506 Top = 0 Action = AcVertAlignBottom end object ToolButton19: TToolButton - Left = 533 + Left = 530 Height = 26 Top = 0 Width = 5 @@ -242,7 +234,7 @@ object Form1: TForm1 Style = tbsDivider end object ToolButton20: TToolButton - Left = 567 + Left = 564 Hint = 'Number format' Top = 0 Caption = 'ToolButton20' @@ -251,7 +243,7 @@ object Form1: TForm1 Style = tbsDropDown end object ToolButton21: TToolButton - Left = 627 + Left = 624 Hint = 'Currency format' Top = 0 Caption = 'ToolButton21' @@ -260,12 +252,12 @@ object Form1: TForm1 Style = tbsDropDown end object ToolButton22: TToolButton - Left = 603 + Left = 600 Top = 0 Action = AcNumFormatPercentage end object ToolButton23: TToolButton - Left = 901 + Left = 898 Height = 26 Top = 0 Width = 5 @@ -273,7 +265,7 @@ object Form1: TForm1 Style = tbsDivider end object ToolButton24: TToolButton - Left = 663 + Left = 660 Hint = 'Date format' Top = 0 Caption = 'ToolButton24' @@ -282,7 +274,7 @@ object Form1: TForm1 Style = tbsDropDown end object ToolButton25: TToolButton - Left = 699 + Left = 696 Hint = 'Time format' Top = 0 Caption = 'ToolButton25' @@ -291,12 +283,12 @@ object Form1: TForm1 Style = tbsDropDown end object ToolButton26: TToolButton - Left = 735 + Left = 732 Top = 0 Action = AcDecDecimals end object ToolButton27: TToolButton - Left = 759 + Left = 756 Top = 0 Action = AcIncDecimals end @@ -307,13 +299,13 @@ object Form1: TForm1 Action = AcCellFontDialog end object ToolButton30: TToolButton - Left = 788 + Left = 785 Hint = 'Background color dialog' Top = 0 Action = AcBackgroundColorDialog end object ToolButton31: TToolButton - Left = 860 + Left = 857 Height = 26 Top = 0 Width = 5 @@ -321,7 +313,7 @@ object Form1: TForm1 Style = tbsDivider end object TbBorders: TToolButton - Left = 865 + Left = 862 Hint = 'Top border' Top = 0 Caption = 'Top' @@ -330,7 +322,7 @@ object Form1: TForm1 Style = tbsDropDown end object ToolButton3: TToolButton - Left = 783 + Left = 780 Height = 26 Top = 0 Width = 5 @@ -338,12 +330,12 @@ object Form1: TForm1 Style = tbsDivider end object ToolButton5: TToolButton - Left = 906 + Left = 903 Top = 0 Action = AcMergeCells end object ToolButton36: TToolButton - Left = 538 + Left = 535 Top = 0 Action = AcWordWrap end @@ -368,6 +360,7 @@ object Form1: TForm1 Width = 130 CellFormatItem = cfiFontName WorkbookSource = WorkbookSource + DropDownCount = 24 ItemIndex = 62 TabOrder = 0 Text = 'Arial' @@ -380,12 +373,13 @@ object Form1: TForm1 Width = 48 CellFormatItem = cfiFontSize WorkbookSource = WorkbookSource + DropDownCount = 24 ItemIndex = 2 TabOrder = 1 Text = '10' end object FontColorCombobox: TsCellCombobox - Left = 235 + Left = 232 Height = 24 Hint = 'Font color' Top = 0 @@ -393,12 +387,13 @@ object Form1: TForm1 CellFormatItem = cfiFontColor ColorRectWidth = -1 WorkbookSource = WorkbookSource + DropDownCount = 24 ItemIndex = 0 TabOrder = 2 Text = 'black' end object BackgroundColorCombobox: TsCellCombobox - Left = 812 + Left = 809 Height = 24 Hint = 'Background color' Top = 0 @@ -406,12 +401,13 @@ object Form1: TForm1 CellFormatItem = cfiBackgroundColor ColorRectWidth = -1 WorkbookSource = WorkbookSource + DropDownCount = 24 ItemIndex = 0 TabOrder = 3 Text = '(none)' end object ToolButton45: TToolButton - Left = 562 + Left = 559 Height = 26 Top = 0 Width = 5 @@ -432,22 +428,22 @@ object Form1: TForm1 Images = ImageList TabOrder = 4 object ToolButton32: TToolButton - Left = 54 + Left = 143 Top = 0 Action = AcAddWorksheet end object ToolButton33: TToolButton - Left = 78 + Left = 167 Top = 0 Action = AcDeleteWorksheet end object ToolButton34: TToolButton - Left = 102 + Left = 191 Top = 0 Action = acRenameWorksheet end object ToolButton1: TToolButton - Left = 232 + Left = 321 Height = 24 Top = 0 Width = 5 @@ -455,7 +451,7 @@ object Form1: TForm1 Style = tbsDivider end object ToolButton2: TToolButton - Left = 237 + Left = 326 Top = 0 Action = AcFileExit end @@ -465,7 +461,7 @@ object Form1: TForm1 Action = AcFileOpen end object ToolButton28: TToolButton - Left = 126 + Left = 215 Height = 24 Top = 0 Width = 5 @@ -478,27 +474,27 @@ object Form1: TForm1 Action = AcFileSaveAs end object ToolButton39: TToolButton - Left = 131 + Left = 220 Top = 0 Action = AcColAdd end object ToolButton40: TToolButton - Left = 155 + Left = 244 Top = 0 Action = AcColDelete end object ToolButton41: TToolButton - Left = 184 + Left = 273 Top = 0 Action = AcRowAdd end object ToolButton42: TToolButton - Left = 208 + Left = 297 Top = 0 Action = AcRowDelete end object ToolButton43: TToolButton - Left = 49 + Left = 138 Height = 24 Top = 0 Width = 5 @@ -506,13 +502,38 @@ object Form1: TForm1 Style = tbsDivider end object ToolButton44: TToolButton - Left = 179 + Left = 268 Height = 24 Top = 0 Width = 5 Caption = 'ToolButton44' Style = tbsDivider end + object ToolButton46: TToolButton + Left = 54 + Top = 0 + Action = AcCopyToClipboard + end + object ToolButton47: TToolButton + Left = 78 + Top = 0 + Action = AcCutToClipboard + end + object ToolButton48: TToolButton + Left = 102 + Top = 0 + Action = AcPasteAllFromClipboard + DropdownMenu = PuPaste + Style = tbsDropDown + end + object ToolButton49: TToolButton + Left = 49 + Height = 24 + Top = 0 + Width = 5 + Caption = 'ToolButton49' + Style = tbsDivider + end end object ToolBar3: TToolBar Left = 0 @@ -1335,12 +1356,57 @@ object Form1: TForm1 ImageIndex = 49 OnExecute = AcColDeleteExecute end + object AcCopyToClipboard: TsCopyAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Copy' + CopyMode = cmCopy + ImageIndex = 51 + ShortCut = 16451 + end + object AcCutToClipboard: TsCopyAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Cut' + CopyMode = cmCut + ImageIndex = 52 + ShortCut = 16472 + end + object AcPasteAllFromClipboard: TsCopyAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Paste all' + CopyItem = ciAll + CopyMode = cmPaste + ImageIndex = 53 + ShortCut = 16470 + end + object AcPasteValueFromClipboard: TsCopyAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Paste value' + CopyItem = ciValue + CopyMode = cmPaste + end + object AcPasteFormatFromClipboard: TsCopyAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Paste format' + CopyMode = cmPaste + end + object AcPasteFormulaFromClipboard: TsCopyAction + Category = 'FPSpreadsheet' + WorkbookSource = WorkbookSource + Caption = 'Paste formula' + CopyItem = ciFormula + CopyMode = cmPaste + end end object ImageList: TImageList left = 176 top = 312 Bitmap = { - 4C693D0000001000000010000000003F9300003F9300003F9300003F9424003F + 4C69400000001000000010000000003F9300003F9300003F9300003F9424003F 948A003E93CC004095CC004095CC004095CC004095CC004095CC004095CC0040 95CC004095CC00409599003F9400003F9300003F9324003F938A0E4B9CD33F76 C0EC5D90D4FF3365A9FFA0A0A0FFA9A9A9FFA9A9A9FFAAAAAAFFACACACFFAEAE @@ -2972,7 +3038,103 @@ object Form1: TForm1 62FFCB8C5DFFC9885BFFC78655FFC28252FFC28252FFC28252FFC28252FFC282 52FFC28252FFBA7642B0FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00C77947AACC8655CECC8857DECB8856DBCC88 + 56DBCB8757DBCA8350D0C479426EB2673C08FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00CA8554D0FFFFFFDBFDF3E9DEFDF3EADEFCF2 + E8DEFAEFE3DEFAF2E7DEEABB88DECF85559CB4693D0AFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00CB8656DAFEF5EDDEFCDEC5DEFBE0C7DEF9DC + C2DEF5D3B4DEFEF9F3DEFAE2C4DEECC193DEC37D4880FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00CB8655DBFEF6F0DEFCE2CDDEFCE3CDDEFADF + C8DEF7D9BCDEF5E9DDDEFAF3EBDEFBF8F3DECD9565DCFFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00CB8655DBFEF7F1DEFCE5D2DEFCE4D1DEFBE2 + CCDEF9DDC4DEEAC39DFFE6BF96FFE4BB92FFE4BB92FFD1A06CF5D09E6DF6CC96 + 5FDAC479427EB2673C09FFFFFF00CB8654DBFFF7F2DEFEE7D5DEFEE7D5DEFDE5 + D1DEFAE0CADEE5BE96FFFFFFFEFFFDF3E9FFFDF3EAFFFCF2E8FFFAEFE3FFFAF2 + E7FFEABB88FFCF8555B3B4693D0CCB8553DBFFF7F0DEFFE7D5DEFDE7D6DEFDE6 + D4DEFCE4D0DEE4BB93FFFEF5EDFFFCDEC5FFFBE0C7FFF9DCC2FFF5D3B4FFFEF9 + F3FFFAE2C4FFECC193FFC37D4893CA8452DBFFF7F1DEFFE9D9DEFFEADBDEFFE9 + D9DEFFE7D7DEE4BB92FFFEF6F0FFFCE2CDFFFCE3CDFFFADFC8FFF7D9BCFFF5E9 + DDFFFAF3EBFFFBF8F3FFCA8353FECC8352DBFBF5EEDEFFE9D9DEFFEADBDEFFE9 + D9DEFFE7D7DEE4BB92FFFEF7F1FFFCE5D2FFFCE4D1FFFBE2CCFFF9DDC4FFF6D7 + BBFFF3D1AFFFFAEFE4FFCC8758FECF8253DEEFF1E7DEFFE9D9DEFFEADBDEFFE9 + D9DEFFE7D7DEE4BB91FFFFF7F2FFFEE7D5FFFEE7D5FFFDE5D1FFFAE0CAFFF9DE + C4FFF7D9BCFFFDF2E7FFCC8757FEC87C4ED3FCF3ECDEFAF1E8DEFAF0E7DEFBF1 + E9DEFBF2EADEE4BA91FFFFF7F0FFFFE7D5FFFDE7D6FFFDE6D4FFFCE4D0FFFBE3 + CBFFFADCC2FFFEF3E8FFCC8656FEC7794AB9C8794BCEC87545DDC77545D4C875 + 45D4C77545D4CA8452FFFFF7F1FFFFE9D9FFFFEADBFFFFE9D9FFFFE7D7FFFFE5 + D2FFFFE2CBFFFFF7F1FFCB8555FEFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00CC8352FBFBF5EEFFFFE9D9FFFFEADBFFFFE9D9FFFFE7D7FFFFE5 + D2FFFFE2CBFFFBF6EFFFCC8355FEFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00CF8253FFEFF1E7FFFFE9D9FFFFEADBFFFFE9D9FFFFE7D7FFFFE5 + D2FFFFE2CBFFEFF2E8FFCE8156FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00C77949EDFCF3ECFFFAF1E8FFFAF0E7FFFBF1E9FFFBF2EAFFFBF2 + EAFFFBF2EBFFFDF4EEFFCA8054F9FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00C57342C1C67545E6C87545FEC77545F3C87545F3C77545F3C775 + 45F3C87546F4C57444E8CA7F53F1FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00996A252AA77B3E9E92611905FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00A67B3E69CBAE87E4905D1409FFFFFF00FFFFFF00FFFF + FF0092601702FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00A97E436ED5BC9DF89261190FFFFFFF00FFFFFF009867 + 222DAE854CB5FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00AB814774DEC8AEFF95641D1EFFFFFF0093601827D1B6 + 93E4BB9767B6FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00AD844C7BE6D4C0FF96651E248F5C121DD3B999DCD3B8 + 97E1915E1518FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00AF875084EDDECEFF97662063CEB38FCBE7D6C3FC9666 + 203BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00B28A5489F1E2D3FFCFB38EF6F5E9DCFFA276376CFFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF005E3D0D02FFFFFF00B68F598BF5E9DDFFE2CDB4FFB99461A0FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF006644121A9D69 + 32ABB17E42D29E682CA4BC9767CDF0E0D0FFB6915FC581531104FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0066431218B17E42DBDCAA + 60FFD09E54F3EAB365FFD8BA99FFF8EBE1FFAE8957BC57390D41FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF009C6A32ACD6A55EFD704D + 1A3E6E4B184FE4AD60FFDCBD9BFFEFCDA5FFEFB767FFD8A65DFF66491D64FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00BE8A4AF2A87E41B6FFFF + FF00966E3297E7B066FFCAA274FEE5B167FF945E2DC1B88D4DD3AF703BF44930 + 0B08FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B58244E7D6A45AE8AE82 + 41C5ECB666FFA76E36D8AC6C37EBC49551F3FFFFFF0076562776B77840FF5238 + 121BFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0077531E56C79751ECD8A6 + 5AFEA66C36CB51350A18A86835E1D1A057FA412A091E8E6A369CB4753FFC4D33 + 0D10FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00674514186A48 + 1620FFFFFF00FFFFFF009F5E2FC6E7B263FFBF924FE5DDAB62FFA26232D8FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF004A310C07A06131D7B6763FF7A46534E04B320C14FFFF + FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF002063982A206398FF2063 + 98FF206398FF206398FF206398FF206398F0FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00FFFFFF00FFFFFF0020639832206398B2206398FF3775A4FFB6EF + FEFF80DBF3FF80DBF3FFB6EFFEFF2E6EA1FF206398FF206398A520639853FFFF + FF00FFFFFF00FFFFFF00FFFFFF00206398E094C9E0FDAEE2F2FF4E9DDFFFB5EE + FDFF75D4F0FF75D4F0FFB5EEFDFF4B9BDEFF8ECBE9FF8DCAE8F2206398F3FFFF + FF00FFFFFF00FFFFFF00FFFFFF00206398FFB0E1F2FF79BDE2FF4498DDFF4497 + DCFF4396DCFF4296DCFF4295DCFF4195DBFF539ED4FF89C6E6FF206398FFFFFF + FF00FFFFFF00FFFFFF00FFFFFF00206398FFAADDF1FF74B9E0FF70B6DFFF6CB3 + DDFF6BB2DCFFD9AF84FFD7AE81FFD7AC7FFFD7AC7FFFCCA070FFCD9F71FFB38F + 67FFCB8856D6B2673C09FFFFFF00206398FFA5DAEFFF6FB5DEFF68B0DCFF60A9 + D9FF5FA9D9FFD7AD81FFFFFFFEFFFDF3E9FFFDF3EAFFFCF2E8FFFAEFE3FFFAF2 + E7FFEABB88FFCE8959E7B4693D0C206398FF9ED6EDFF6BB2DCFF66AFDCFF60AA + DAFF5FA9D9FFD9AF84FFFEF5EDFFFCDEC5FFFBE0C7FFF9DCC2FFF5D3B4FFFEF9 + F3FFFAE2C4FFECC193FFCB8857DC206398FF98D2EBFF65AEDAFF60AAD9FF5DA6 + D8FF5CA5D7FFD9AF84FFFEF6F0FFFCE2CDFFFCE3CDFFFADFC8FFF7D9BCFFF5E9 + DDFFFAF3EBFFFBF8F3FFCA8353FE206398FF91CDE9FF5FA9D9FF5DA5D8FF5AA0 + D6FF599FD6FFD8AD81FFFEF7F1FFFCE5D2FFFCE4D1FFFBE2CCFFF9DDC4FFF6D7 + BBFFF3D1AFFFFAEFE4FFCC8758FE206398FF8BC9E7FF5CA5D7FF59A0D5FF579C + D3FF569AD3FFD7AC7FFFFFF7F2FFFEE7D5FFFEE7D5FFFDE5D1FFFAE0CAFFF9DE + C4FFF7D9BCFFFDF2E7FFCC8757FE206398FF88C4E6FF599FD6FF569BD3FF5397 + D1FF5395D1FFD7AC7FFFFFF7F0FFFFE7D5FFFDE7D6FFFDE6D4FFFCE4D0FFFBE3 + CBFFFADCC2FFFEF3E8FFCC8656FE206398FF84BFE2FF569AD3FF5397D1FF5092 + CFFF5091CFFFD6A97DFFFFF7F1FFFFE9D9FFFFEADBFFFFE9D9FFFFE7D7FFFFE5 + D2FFFFE2CBFFFFF7F1FFCB8555FE206398FF80B9E1FF5395D1FF5092D0FF4E8E + CEFF4D8CCDFFD6A97DFFFBF5EEFFFFE9D9FFFFEADBFFFFE9D9FFFFE7D7FFFFE5 + D2FFFFE2CBFFFBF6EFFFCC8355FE206398C274ADD8FF7BB2DDFF78AEDCFF75AA + DAFF74A9DAFFDAA97DFFEFF1E7FFFFE9D9FFFFEADBFFFFE9D9FFFFE7D7FFFFE5 + D2FFFFE2CBFFEFF2E8FFCE8156FF2063984A206398CF206398FF206398FF2063 + 98FF206398FFC98F67FFFCF3ECFFFAF1E8FFFAF0E7FFFBF1E9FFFBF2EAFFFBF2 + EAFFFBF2EBFFFDF4EEFFCA8054F9FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF + FF00FFFFFF00C57342C1C67545E6C87545FEC77545F3C87545F3C77545F3C775 + 45F3C87546F4C57444E8CA7F53F1FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003B7F320015A9000015A9000015A9 000015A9000015AA009915AA00CC15AA00CC15AA009915A9000015A9000015A9 @@ -3424,6 +3586,33 @@ object Form1: TForm1 end object MnuEdit: TMenuItem Caption = 'Edit' + object MenuItem101: TMenuItem + Action = AcCopyToClipboard + end + object MenuItem100: TMenuItem + Action = AcCutToClipboard + end + object MenuItem99: TMenuItem + Caption = 'Paste' + object MenuItem102: TMenuItem + Action = AcPasteAllFromClipboard + end + object MenuItem103: TMenuItem + Caption = '-' + end + object MenuItem104: TMenuItem + Action = AcPasteValueFromClipboard + end + object MenuItem105: TMenuItem + Action = AcPasteFormulaFromClipboard + end + object MenuItem106: TMenuItem + Action = AcPasteFormatFromClipboard + end + end + object MenuItem98: TMenuItem + Caption = '-' + end object MnuWorksheet: TMenuItem Caption = 'Worksheet' object MnuAddSheet: TMenuItem @@ -4996,4 +5185,23 @@ object Form1: TForm1 } end end + object PuPaste: TPopupMenu + left = 504 + top = 471 + object MenuItem9: TMenuItem + Action = AcPasteAllFromClipboard + end + object MenuItem94: TMenuItem + Caption = '-' + end + object MenuItem95: TMenuItem + Action = AcPasteValueFromClipboard + end + object MenuItem96: TMenuItem + Action = AcPasteFormatFromClipboard + end + object MenuItem97: TMenuItem + Action = AcPasteFormulaFromClipboard + end + end end diff --git a/components/fpspreadsheet/examples/fpsctrls/main.pas b/components/fpspreadsheet/examples/fpsctrls/main.pas index 342483adf..1d8b4a881 100644 --- a/components/fpspreadsheet/examples/fpsctrls/main.pas +++ b/components/fpspreadsheet/examples/fpsctrls/main.pas @@ -27,6 +27,13 @@ type MainMenu: TMainMenu; MenuItem1: TMenuItem; MenuItem10: TMenuItem; + MenuItem100: TMenuItem; + MenuItem101: TMenuItem; + MenuItem102: TMenuItem; + MenuItem103: TMenuItem; + MenuItem104: TMenuItem; + MenuItem105: TMenuItem; + MenuItem106: TMenuItem; MenuItem11: TMenuItem; MenuItem12: TMenuItem; MenuItem13: TMenuItem; @@ -110,8 +117,14 @@ type MenuItem87: TMenuItem; MenuItem88: TMenuItem; MenuItem89: TMenuItem; + MenuItem9: TMenuItem; MenuItem90: TMenuItem; MenuItem91: TMenuItem; + MenuItem95: TMenuItem; + MenuItem96: TMenuItem; + MenuItem97: TMenuItem; + MenuItem98: TMenuItem; + MenuItem99: TMenuItem; MnuColumn: TMenuItem; MenuItem93: TMenuItem; MenuItem94: TMenuItem; @@ -150,6 +163,7 @@ type AcNumFormatCurrency: TsNumberFormatAction; AcNumFormatCurrencyRed: TsNumberFormatAction; Panel2: TPanel; + PuPaste: TPopupMenu; PuBorders: TPopupMenu; PuTimeFormat: TPopupMenu; PuDateFormat: TPopupMenu; @@ -191,6 +205,12 @@ type FontnameCombo: TsCellCombobox; FontsizeCombo: TsCellCombobox; AcMergeCells: TsMergeAction; + AcCopyToClipboard: TsCopyAction; + AcCutToClipboard: TsCopyAction; + AcPasteAllFromClipboard: TsCopyAction; + AcPasteValueFromClipboard: TsCopyAction; + AcPasteFormatFromClipboard: TsCopyAction; + AcPasteFormulaFromClipboard: TsCopyAction; Splitter2: TSplitter; Splitter3: TSplitter; ToolBar2: TToolBar; @@ -238,13 +258,16 @@ type ToolButton37: TToolButton; ToolButton38: TToolButton; ToolButton39: TToolButton; - ToolButton4: TToolButton; ToolButton40: TToolButton; ToolButton41: TToolButton; ToolButton42: TToolButton; ToolButton43: TToolButton; ToolButton44: TToolButton; ToolButton45: TToolButton; + ToolButton46: TToolButton; + ToolButton47: TToolButton; + ToolButton48: TToolButton; + ToolButton49: TToolButton; ToolButton5: TToolButton; ToolButton6: TToolButton; ToolButton7: TToolButton; diff --git a/components/fpspreadsheet/fpsactions.pas b/components/fpspreadsheet/fpsactions.pas index a15656cff..2605e1e85 100644 --- a/components/fpspreadsheet/fpsactions.pas +++ b/components/fpspreadsheet/fpsactions.pas @@ -108,16 +108,19 @@ type { --- Actions related to cell and cell selection formatting--- } TsCopyItem = (ciFormat, ciValue, ciFormula, ciAll); + TsCopyMode = (cmBrush, cmCopy, cmCut, cmPaste); TsCopyAction = class(TsSpreadsheetAction) private FCopyItem: TsCopyItem; + FCopyMode: TsCopyMode; public procedure ExecuteTarget(Target: TObject); override; procedure UpdateTarget(Target: TObject); override; published property Caption; property CopyItem: TsCopyItem read FCopyItem write FCopyItem default ciFormat; + property CopyMode: TsCopyMode read FCopyMode write FCopyMode default cmBrush; property Enabled; property HelpContext; property HelpKeyword; @@ -685,19 +688,46 @@ end; procedure TsCopyAction.ExecuteTarget(Target: TObject); const - OPERATIONS: array[TsCopyItem] of TsPendingOperation = ( - poCopyFormat, poCopyValue, poCopyFormula, poCopyCell + OPERATIONS: array[TsCopyItem] of TsCopyOperation = ( + coCopyFormat, coCopyValue, coCopyFormula, coCopyCell ); begin Unused(Target); - Checked := true; - WorkbookSource.SetPendingOperation(OPERATIONS[FCopyItem], Worksheet.GetSelection); + case FCopyMode of + cmBrush: + begin + Checked := true; + WorkbookSource.SetPendingOperation(OPERATIONS[FCopyItem], Worksheet.GetSelection); + end; + cmCopy: + begin + Checked := false; + WorkbookSource.CopyCellsToClipboard; + end; + cmCut: + begin + Checked := false; + WorkbookSource.CutCellsToClipboard; + end; + cmPaste: + begin + Checked := false; + WorkbookSource.PasteCellsFromClipboard(OPERATIONS[FCopyItem]); + end; + end; end; procedure TsCopyAction.UpdateTarget(Target: TObject); begin Unused(Target); - if WorkbookSource.PendingOperation = poNone then Checked := false; + case FCopyMode of + cmBrush: + if WorkbookSource.PendingOperation = coNone then Checked := false; + cmCopy, cmCut: + Enabled := Worksheet.GetSelectionCount > 0; + cmPaste: + Enabled := not WorkbookSource.CellClipboardEmpty; + end; end; diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index fc70b6d10..58703c9ad 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -783,6 +783,9 @@ type procedure CopyValue(AFromCell, AToCell: PCell); overload; procedure CopyValue(AValueCell: PCell; AToRow, AToCol: Cardinal); overload; + procedure DeleteCell(ACell: PCell); + procedure EraseCell(ACell: PCell); + procedure ExchangeCells(ARow1, ACol1, ARow2, ACol2: Cardinal); function FindCell(ARow, ACol: Cardinal): PCell; overload; @@ -793,6 +796,7 @@ type function GetCellCount: Cardinal; function GetFirstCell(): PCell; function GetNextCell(): PCell; + function GetFirstCellOfRow(ARow: Cardinal): PCell; function GetLastCellOfRow(ARow: Cardinal): PCell; function GetFirstColIndex(AForceCalculation: Boolean = false): Cardinal; @@ -1322,7 +1326,7 @@ procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer); function SameCellBorders(ACell1, ACell2: PCell): Boolean; procedure InitCell(var ACell: TCell); overload; -procedure InitCell(ARow, ACol: Cardinal; var ACell: TCell); overload; +procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); overload; function HasFormula(ACell: PCell): Boolean; @@ -1590,7 +1594,7 @@ end; @param ACol Column index of the new cell @return New cell record with row and column fields preset to passed values. -------------------------------------------------------------------------------} -procedure InitCell(ARow, ACol: Cardinal; var ACell: TCell); +procedure InitCell(ARow, ACol: Cardinal; out ACell: TCell); begin InitCell(ACell); ACell.Row := ARow; @@ -2084,6 +2088,37 @@ begin CopyValue(AValueCell, GetCell(AToRow, AToCol)); end; +{@@ ---------------------------------------------------------------------------- + Deletes a specified cell. If the cell belongs to a merged block its content + and formatting is erased. Otherwise the cell is destroyed, its memory is + released. +-------------------------------------------------------------------------------} +procedure TsWorksheet.DeleteCell(ACell: PCell); +begin + if ACell = nil then + exit; + + // Is base of merged block? unmerge the block + if ACell^.MergeBase = ACell then + UnmergeCells(ACell^.Row, ACell^.Col); + + // Belongs to a merged block? + if ACell^.MergeBase <> nil then begin + EraseCell(ACell); + exit; + end; + + // Is base of shared formula block? Recreate individual formulas + if ACell^.SharedFormulaBase = ACell then + SplitSharedFormula(ACell); + + // Belongs to shared formula block? --> nothing to do + + // Destroy the cell, and remove it from the tree + RemoveAndFreeCell(ACell^.Row, ACell^.Col); +end; + + {@@ ---------------------------------------------------------------------------- Internal call-back procedure for looping through all cells when deleting a specified column. Deletion happens in DeleteCol BEFORE this callback! @@ -2194,6 +2229,22 @@ begin end; end; +{@@ ---------------------------------------------------------------------------- + Erases content and formatting of a cell. The cell still occupies memory. + + @param ACell Pointer to cell to be erased. +-------------------------------------------------------------------------------} +procedure TsWorksheet.EraseCell(ACell: PCell); +var + r, c: Cardinal; +begin + if ACell <> nil then begin + r := ACell^.Row; + c := ACell^.Col; + InitCell(r, c, ACell^); + end; +end; + {@@ ---------------------------------------------------------------------------- Exchanges two cells @@ -3494,7 +3545,7 @@ end; {@@ ---------------------------------------------------------------------------- Removes a cell and releases its memory. - Just for internal usage since it does not modify the other cells affects + Just for internal usage since it does not modify the other cells affected @param ARow Row index of the cell to be removed @param ACol Column index of the cell to be removed @@ -3877,7 +3928,7 @@ end; {@@ ---------------------------------------------------------------------------- Splits a shared formula range to which the specified cell belongs into - individual cells. Each cell gets same the formula as it had in the block. + individual cells. Each cell gets the same formula as it had in the block. This is required because insertion and deletion of columns/rows make shared formulas very complicated. -------------------------------------------------------------------------------} diff --git a/components/fpspreadsheet/fpspreadsheetctrls.pas b/components/fpspreadsheet/fpspreadsheetctrls.pas index d79fe1717..29a5769c6 100644 --- a/components/fpspreadsheet/fpspreadsheetctrls.pas +++ b/components/fpspreadsheet/fpspreadsheetctrls.pas @@ -45,8 +45,8 @@ type controls and describes which items have changed in the spreadsheet. } TsNotificationItems = set of TsNotificationItem; - {@@ Identifier for an operation that will be executed at next cell select } - TsPendingOperation = (poNone, poCopyFormat, poCopyValue, poCopyFormula, poCopyCell); + {@@ Identifier for an copy operation } + TsCopyOperation = (coNone, coCopyFormat, coCopyValue, coCopyFormula, coCopyCell); { TsWorkbookSource } @@ -61,7 +61,8 @@ type FFileName: TFileName; FFileFormat: TsSpreadsheetFormat; FPendingSelection: TsCellRangeArray; - FPendingOperation: TsPendingOperation; + FPendingOperation: TsCopyOperation; + FCutPending: Boolean; FControlLockCount: Integer; FOptions: TsWorkbookOptions; FOnError: TsWorkbookSourceErrorEvent; @@ -115,16 +116,23 @@ type procedure SelectWorksheet(AWorkSheet: TsWorksheet); procedure ExecutePendingOperation; - procedure SetPendingOperation(AOperation: TsPendingOperation; + procedure SetPendingOperation(AOperation: TsCopyOperation; const ASelection: TsCellRangeArray); + { Clipboard } + function CellClipboardEmpty: Boolean; + procedure ClearCellClipboard; + procedure CopyCellsToClipboard; + procedure CutCellsToClipboard; + procedure PasteCellsFromClipboard(AItem: TsCopyOperation); + public {@@ Workbook linked to the WorkbookSource } property Workbook: TsWorkbook read FWorkbook; {@@ Currently selected worksheet of the workbook } property Worksheet: TsWorksheet read FWorksheet; {@@ Indicates that which operation is waiting to be executed at next cell select } - property PendingOperation: TsPendingOperation read FPendingOperation; + property PendingOperation: TsCopyOperation read FPendingOperation; published {@@ Automatically detects the fileformat when loading the spreadsheet file @@ -408,7 +416,6 @@ type property FixedCols default 0; end; - procedure Register; @@ -428,12 +435,119 @@ begin RegisterComponents('FPSpreadsheet', [ TsWorkbookSource, TsWorkbookTabControl, TsWorksheetGrid, TsCellEdit, TsCellIndicator, TsCellCombobox, - //TsFontNameCombobox, TsFontSizeCombobox, TsSpreadsheetInspector ]); end; +{------------------------------------------------------------------------------} +{ TsCellList } +{------------------------------------------------------------------------------} + +type + TsCellList = class(TList) + private + function GetCell(AIndex: Integer): PCell; + procedure SetCell(AIndex: Integer; ACell: PCell); + public + destructor Destroy; + function Add(ACell: PCell): Integer; + function AddCell(ACell: PCell): Integer; + function AddEmptyCell(ARow, ACol: Cardinal): Integer; + procedure Clear; override; + procedure Delete(AIndex: Integer); + function IndexOf(ACell: PCell): Integer; + property CellByIndex[AIndex: Integer]: PCell read GetCell write SetCell; + end; + +var + CellClipboard: TsCellList = nil; + +destructor TsCellList.Destroy; +begin + Clear; + inherited; +end; + +function TsCellList.Add(ACell: PCell): Integer; +begin + Result := AddCell(ACell); +end; + +{ Adds a copy of a specific cell to the list } +function TsCellList.AddCell(ACell: PCell): Integer; +var + cell: PCell; +begin + if ACell = nil then + raise Exception.Create('[TsCellList.AddCell] Cell is nil, use AddEmptyCell.'); + Result := IndexOf(ACell); + if Result = - 1 then + begin + New(cell); + cell^ := ACell^; + Result := inherited Add(cell); + end; +end; + +{ Adds a "non-existing" cell to the list. Such a cell is nil in the worksheet. + Here it has ContentType = cctEmpty and UsedFormattingFields = [], i.e. it is + an empty cell without formatting. } +function TsCellList.AddEmptyCell(ARow, ACol: Cardinal): Integer; +var + cell: PCell; +begin + New(cell); + InitCell(ARow, ACol, cell^); + Result := inherited Add(cell); +end; + +procedure TsCellList.Clear; +var + i: Integer; +begin + for i := Count-1 downto 0 do + Delete(i); + inherited Clear; +end; + +procedure TsCellList.Delete(AIndex: Integer); +var + cell: PCell; +begin + cell := GetCell(AIndex); + Dispose(cell); + inherited Delete(AIndex); +end; + +function TsCellList.GetCell(AIndex: Integer): PCell; +begin + Result := PCell(inherited Items[AIndex]); +end; + +function TsCellList.IndexOf(ACell: PCell): Integer; +var + cell: PCell; +begin + for Result:=0 to Count-1 do + begin + cell := GetCell(Result); + if (cell^.Row = ACell^.Row) and (cell^.Col = ACell^.Col) then + exit; + end; + Result := -1; +end; + +procedure TsCellList.SetCell(AIndex: Integer; ACell: PCell); +var + cell: PCell; +begin + cell := GetCell(AIndex); + cell^ := ACell^; +end; + + + {------------------------------------------------------------------------------} { TsWorkbookSource } {------------------------------------------------------------------------------} @@ -539,10 +653,10 @@ begin Unused(ARow, ACol); NotifyListeners([lniSelection]); - if FPendingOperation <> poNone then + if FPendingOperation <> coNone then begin ExecutePendingOperation; - FPendingOperation := poNone; + FPendingOperation := coNone; end; end; @@ -638,10 +752,10 @@ begin srcCell := Worksheet.FindCell(FPendingSelection[i].Row1+j, FPendingSelection[i].Col1+k); destCell := Worksheet.GetCell(destSelection[i].Row1+j, destSelection[i].Col1+k); case FPendingOperation of - poCopyCell : Worksheet.CopyCell(srcCell, destCell); - poCopyFormat : Worksheet.CopyFormat(srcCell, destCell); - poCopyFormula: Worksheet.CopyFormula(srcCell, destCell); - poCopyValue : Worksheet.CopyValue(srcCell, destCell); + coCopyCell : Worksheet.CopyCell(srcCell, destCell); + coCopyFormat : Worksheet.CopyFormat(srcCell, destCell); + coCopyFormula: Worksheet.CopyFormula(srcCell, destCell); + coCopyValue : Worksheet.CopyValue(srcCell, destCell); end; end; end; @@ -953,7 +1067,7 @@ end; Defines a "pending operation" which will be executed at next cell select. Source of the operation is the selection passes as a parameter. -------------------------------------------------------------------------------} -procedure TsWorkbookSource.SetPendingOperation(AOperation: TsPendingOperation; +procedure TsWorkbookSource.SetPendingOperation(AOperation: TsCopyOperation; const ASelection: TsCellRangeArray); var i: Integer; @@ -965,6 +1079,117 @@ begin FPendingOperation := AOperation; end; +{@@ ---------------------------------------------------------------------------- + Checks whether the internal "Clipboard" is empty or not. +-------------------------------------------------------------------------------} +function TsWorkbookSource.CellClipboardEmpty: Boolean; +begin + Result := CellClipboard.Count = 0; +end; + +{@@ ---------------------------------------------------------------------------- + Clears the interal "Clipboard". Note that this is not the system clipboard. +-------------------------------------------------------------------------------} +procedure TsWorkbookSource.ClearCellClipboard; +begin + CellClipboard.Clear; +end; + +{@@ ---------------------------------------------------------------------------- + Copies the selected cells of the worksheet to an internal list ("Clipboard"). + Note that this is not the system clipboard in the current implementation. +-------------------------------------------------------------------------------} +procedure TsWorkbookSource.CopyCellsToClipboard; +var + r,c,i: Integer; + sel: TsCellRangeArray; + cell: PCell; +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 + for c := sel[i].Col1 to sel[i].Col2 do + begin + cell := FWorksheet.FindCell(r, c); + if cell = nil then + CellClipboard.AddEmptyCell(r, c) + else + CellClipboard.AddCell(cell); + end; +end; + +{@@ ---------------------------------------------------------------------------- + Copies the selected cells of the worksheet to an internal list ("Clipboard") + and sets the marker "CutPending". This means that the source cells will be + cleared when PasteCellsFromClipboard is called. + Note that the clipboard is not the system clipboard in the current + implementation. +-------------------------------------------------------------------------------} +procedure TsWorkbookSource.CutCellsToClipboard; +begin + CopyCellsToClipboard; + FCutPending := true; +end; + +{@@ ---------------------------------------------------------------------------- + Pastes the cells stored in the internal list "Clipboard" into the worksheet. + Using their stored row/col indexes the stored cells are translated such that + the first stored cell appears at the currently active cell in the worksheet. +-------------------------------------------------------------------------------} +procedure TsWorkbookSource.PasteCellsFromClipboard(AItem: TsCopyOperation); +var + r, c, dr, dc: LongInt; + i: Integer; + cell: PCell; +begin + if CellClipboard.Count = 0 then + exit; + + DisableControls; + try + if FCutPending then + begin + for i:=0 to CellClipboard.Count-1 do + begin + cell := CellClipboard.CellByIndex[i]; + r := cell^.Row; + c := cell^.Col; + cell := FWorksheet.FindCell(r, c); + FWorksheet.DeleteCell(cell); + end; + FCutPending := false; + end; + + cell := CellClipboard.CellByIndex[0]; + dr := FWorksheet.ActiveCellRow - cell^.Row; + dc := FWorksheet.ActiveCellCol - cell^.Col; + + for i:=0 to CellClipboard.Count-1 do + begin + cell := CellClipboard.CellByIndex[i]; + case AItem of + coCopyCell: + FWorksheet.CopyCell(cell^.Row, cell^.Col, cell^.Row + dr, cell^.Col + dc); + coCopyValue: + FWorksheet.CopyValue(cell, cell^.Row + dr, cell^.Col + dc); + coCopyFormat: + FWorksheet.CopyFormat(cell, cell^.Row + dr, cell^.Col + dc); + coCopyFormula: + FWorksheet.CopyFormula(cell, cell^.Row + dr, cell^.Col + dc); + end; + end; + + finally + EnableControls; + end; +end; + {@@ ---------------------------------------------------------------------------- Event handler called whenever the palette of the workbook is changed. -------------------------------------------------------------------------------} @@ -2479,7 +2704,12 @@ begin end; initialization + CellClipboard := TsCellList.Create; + + {$I fpspreadsheetctrls.lrs} + +finalization + CellClipboard.Free; -{$I fpspreadsheetctrls.lrs} end.