Source code for wolfhece.CpGrid

import wx
import wx.grid

from .PyTranslate import _

[docs] class CpGrid(wx.grid.Grid): """ A Full Copy and Paste enabled grid class which implements Excel like copy, paste, and delete functionality. - Ctrl+c : Copy range of selected cells. - Ctrl+v : Paste copy selection at point of currently selected cell. - If paste selection is larger than copy selection, copy selection will be replicated to fill paste region if it is a modulo number of copy rows and/or columns, otherwise just the copy selection will be pasted. - Ctrl+x : Delete current selection. - Deleted selection can be restored with Ctrl+z, or pasted with Ctrl+v. - Delete or backspace key will also perform this action. - Ctrl+z : Undo the last paste or delete action. """ def __init__(self, parent, id, style): wx.grid.Grid.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, style) # bind key down events self.Bind(wx.EVT_KEY_DOWN, self.OnKey) # initialize text string for undo (start row, start col, undo string) self.data4undo = [0, 0, ''] # initialize copy rows and columns # catches case of initial Ctrl+v before a Ctrl+c self.crows = 1 self.ccols = 1 # initialize clipboard to empty string data = '' # Create text data object clipboard = wx.TextDataObject() # Set data object value clipboard.SetText(data) # Put the data in the clipboard if wx.TheClipboard.Open(): wx.TheClipboard.SetData(clipboard) wx.TheClipboard.Close() else: wx.MessageBox("Can't open the clipboard", "Error")
[docs] def OnKey(self, event): """Handles all key events. """ # If Ctrl+c is pressed... if event.ControlDown() and event.GetKeyCode() == 67: self.copy() # If Ctrl+v is pressed... if event.ControlDown() and event.GetKeyCode() == 86: self.paste('paste') # If Ctrl+Z is pressed... if event.ControlDown() and event.GetKeyCode() == 90: if self.data4undo[2] != '': self.paste('undo') # If del, backspace or Ctrl+x is pressed... if event.GetKeyCode() == 127 or event.GetKeyCode() == 8 \ or (event.ControlDown() and event.GetKeyCode() == 88): # Call delete method self.delete() # if event.GetKeyCode() == wx.WXK_RETURN: # self.SetGridCursor(self.GetGridCursorRow()-1,self.GetGridCursorCol()+1) # Skip other Key events if event.GetKeyCode(): event.Skip() return
[docs] def copy(self): """Copies the current range of select cells to clipboard. """ # Get number of copy rows and cols if len(self.GetSelectionBlockTopLeft()) == 0: rowstart = self.GetGridCursorRow() colstart = self.GetGridCursorCol() rowend = rowstart colend = colstart else: rowstart = self.GetSelectionBlockTopLeft()[0][0] colstart = self.GetSelectionBlockTopLeft()[0][1] rowend = self.GetSelectionBlockBottomRight()[0][0] colend = self.GetSelectionBlockBottomRight()[0][1] self.crows = rowend - rowstart + 1 self.ccols = colend - colstart + 1 # data variable contains text that must be set in the clipboard data = '' # For each cell in selected range append the cell value # in the data variable Tabs '\t' for cols and '\n' for rows for r in range(self.crows): for c in range(self.ccols): data += str(self.GetCellValue(rowstart + r, colstart + c)) if c < self.ccols - 1: data += '\t' data += '\n' # Create text data object clipboard = wx.TextDataObject() # Set data object value clipboard.SetText(data) # Put the data in the clipboard if wx.TheClipboard.Open(): wx.TheClipboard.SetData(clipboard) wx.TheClipboard.Close() else: wx.MessageBox("Can't open the clipboard", "Error")
[docs] def build_paste_selection(self): """This method creates the paste selection, builds it into a clipboard string, and puts it on the clipboard. When building the paste selection it fills in replicas of the copy selection if: number of rows and/or columns in the paste selection is larger than the copy selection, and they are multiples of the corresponding copy selection rows and/or columns, otherwise just the copy selection will be used. """ # Get number of copy rows and cols if len(self.GetSelectionBlockTopLeft()) == 0: rowstart = self.GetGridCursorRow() colstart = self.GetGridCursorCol() rowend = rowstart colend = colstart else: rowstart = self.GetSelectionBlockTopLeft()[0][0] colstart = self.GetSelectionBlockTopLeft()[0][1] rowend = self.GetSelectionBlockBottomRight()[0][0] colend = self.GetSelectionBlockBottomRight()[0][1] self.prows = rowend - rowstart + 1 self.pcols = colend - colstart + 1 # find if paste selection area is a multiple of the copy selection rows_mod = not(bool(self.prows % self.crows)) cols_mod = not(bool(self.pcols % self.ccols)) # initialize to default case (i.e. paste equals copy) row_copies = 1 col_copies = 1 # one row multiple column paste selection if self.prows == 1 and self.pcols > 1 and cols_mod: col_copies = int(self.pcols / self.ccols) # int division # one col multiple row paste selection if self.prows > 1 and rows_mod and self.pcols == 1: row_copies = int(self.prows / self.crows) # int division # mulitple row and column paste selection if self.prows > 1 and rows_mod and self.pcols > 1 and cols_mod: row_copies = int(self.prows / self.crows) # int division col_copies = int(self.pcols / self.ccols) # int division clipboard = wx.TextDataObject() if wx.TheClipboard.Open(): wx.TheClipboard.GetData(clipboard) wx.TheClipboard.Close() else: wx.MessageBox("Can't open the clipboard", "Error") data = clipboard.GetText() # column expansion (fill out additional columns) out_values = [] for row, text in enumerate(data.splitlines()): string = text for i in range(col_copies - 1): string += '\t' + text out_values.append(string) # row expansion (fill out additional rows) out_values *= row_copies # build output text string for clipboard self.out_data = '\n'.join(out_values)
[docs] def paste(self, mode): """Handles paste and undo operations. """ # perform paste or undo action if mode == 'paste': # create the paste string from the copy string self.build_paste_selection() if len(self.GetSelectionBlockTopLeft()) == 0: rowstart = self.GetGridCursorRow() colstart = self.GetGridCursorCol() else: rowstart = self.GetSelectionBlockTopLeft()[0][0] colstart = self.GetSelectionBlockTopLeft()[0][1] elif mode == 'undo': self.out_data = self.data4undo[2] rowstart = self.data4undo[0] colstart = self.data4undo[1] else: wx.MessageBox("Paste method " + mode + " does not exist", "Error") # paste current paste selection and build a clipboard string for undo text4undo = '' # initialize for y, r in enumerate(self.out_data.splitlines()): # Convert c in a array of text separated by tab for x, c in enumerate(r.split('\t')): if y + rowstart < self.NumberRows and \ x + colstart < self.NumberCols: text4undo += str(self.GetCellValue(rowstart + y, colstart + x)) + '\t' self.SetCellValue(rowstart + y, colstart + x, c) text4undo = text4undo[:-1] + '\n' # save current paste selection for undo if mode == 'paste': self.data4undo = [rowstart, colstart, text4undo] else: self.data4undo = [0, 0, '']
[docs] def delete(self): """This method deletes text from selected cells, places a copy of the deleted cells on the clipboard for pasting (Ctrl+v), and places a copy in the self.data4undo variable for undoing (Ctrl+z) """ # Get number of delete rows and cols if len(self.GetSelectionBlockTopLeft()) == 0: rowstart = self.GetGridCursorRow() colstart = self.GetGridCursorCol() rowend = rowstart colend = colstart else: rowstart = self.GetSelectionBlockTopLeft()[0][0] colstart = self.GetSelectionBlockTopLeft()[0][1] rowend = self.GetSelectionBlockBottomRight()[0][0] colend = self.GetSelectionBlockBottomRight()[0][1] rows = rowend - rowstart + 1 cols = colend - colstart + 1 # Save deleted text and clear cells contents text4undo = '' for r in range(rows): for c in range(cols): text4undo += \ str(self.GetCellValue(rowstart + r, colstart + c)) + '\t' self.SetCellValue(rowstart + r, colstart + c, '') text4undo = text4undo[:-1] + '\n' # Save a copy of deleted text for undo self.data4undo = [rowstart, colstart, text4undo] # Save a copy of deleted text to clipboard for Ctrl+v clipboard = wx.TextDataObject() clipboard.SetText(text4undo) if wx.TheClipboard.Open(): wx.TheClipboard.SetData(clipboard) wx.TheClipboard.Close() else: wx.MessageBox("Can't open the clipboard", "Error")