1# (C) Copyright 2005-2020 Enthought, Inc., Austin, TX 2# All rights reserved. 3# 4# This software is provided without warranty under the terms of the BSD 5# license included in LICENSE.txt and may be redistributed only under 6# the conditions described in the aforementioned license. The license 7# is also available online at http://www.enthought.com/licenses/BSD.txt 8# 9# Thanks for using Enthought open source! 10 11 12from wx.grid import ( 13 Grid, 14 PyGridTableBase, 15 GridCellAttr, 16 GridTableMessage, 17 GridCellFloatRenderer, 18) 19from wx.grid import ( 20 GRIDTABLE_NOTIFY_ROWS_DELETED, 21 GRIDTABLE_NOTIFY_ROWS_APPENDED, 22) 23from wx.grid import ( 24 GRIDTABLE_NOTIFY_COLS_DELETED, 25 GRIDTABLE_NOTIFY_COLS_APPENDED, 26) 27from wx.grid import GRIDTABLE_REQUEST_VIEW_GET_VALUES 28from wx.grid import GRID_VALUE_BOOL 29from wx import ALIGN_LEFT, ALIGN_CENTRE, Colour 30 31from .default_renderer import DefaultRenderer 32 33 34class VirtualModel(PyGridTableBase): 35 """ 36 A custom wxGrid Table that expects a user supplied data source. 37 THIS CLASS IS NOT LIMITED TO ONLY DISPLAYING LOG DATA! 38 """ 39 40 def __init__(self, data, column_names): 41 """data is currently a list of the form 42 [(rowname, dictionary), 43 dictionary.get(colname, None) returns the data for a cell 44 """ 45 ##print 'Initializing virtual model' 46 PyGridTableBase.__init__(self) 47 self.set_data_source(data) 48 self.colnames = column_names 49 # self.renderers = {"DEFAULT_RENDERER":DefaultRenderer()} 50 # self.editors = {} 51 52 # we need to store the row length and col length to see if the table has changed size 53 self._rows = self.GetNumberRows() 54 self._cols = self.GetNumberCols() 55 56 # ------------------------------------------------------------------------------- 57 # Implement/override the methods from PyGridTableBase 58 # ------------------------------------------------------------------------------- 59 60 def GetNumberCols(self): 61 return len(self.colnames) 62 63 def GetNumberRows(self): 64 return len(self._data) 65 66 def GetColLabelValue(self, col): 67 return self.colnames[col] 68 69 def GetRowLabelValue(self, row): 70 return self._data[row][0] 71 72 def GetValue(self, row, col): 73 return str(self._data[row][1].get(self.GetColLabelValue(col), "")) 74 75 def GetRawValue(self, row, col): 76 return self._data[row][1].get(self.GetColLabelValue(col), "") 77 78 def SetValue(self, row, col, value): 79 print("Setting value %d %d %s" % (row, col, value)) 80 print("Before ", self.GetValue(row, col)) 81 self._data[row][1][self.GetColLabelValue(col)] = value 82 print("After ", self.GetValue(row, col)) 83 84 """ def GetTypeName(self, row, col): 85 if col == 2 or col == 6: 86 res = "MeasurementUnits" 87 elif col == 7: 88 res = GRID_VALUE_BOOL 89 else: 90 res = self.base_GetTypeName(row, col) 91 # print 'asked for type of col ', col, ' ' ,res 92 return res""" 93 94 # ------------------------------------------------------------------------------- 95 # Accessors for the Enthought data model (a dict of dicts) 96 # ------------------------------------------------------------------------------- 97 def get_data_source(self): 98 """ The data structure we provide the data in. 99 """ 100 return self._data 101 102 def set_data_source(self, source): 103 self._data = source 104 return 105 106 # ------------------------------------------------------------------------------- 107 # Methods controlling updating and editing of cells in grid 108 # ------------------------------------------------------------------------------- 109 110 def ResetView(self, grid): 111 """ 112 (wxGrid) -> Reset the grid view. Call this to 113 update the grid if rows and columns have been added or deleted 114 """ 115 ##print 'VirtualModel.reset_view' 116 grid.BeginBatch() 117 for current, new, delmsg, addmsg in [ 118 ( 119 self._rows, 120 self.GetNumberRows(), 121 GRIDTABLE_NOTIFY_ROWS_DELETED, 122 GRIDTABLE_NOTIFY_ROWS_APPENDED, 123 ), 124 ( 125 self._cols, 126 self.GetNumberCols(), 127 GRIDTABLE_NOTIFY_COLS_DELETED, 128 GRIDTABLE_NOTIFY_COLS_APPENDED, 129 ), 130 ]: 131 if new < current: 132 msg = GridTableMessage(self, delmsg, new, current - new) 133 grid.ProcessTableMessage(msg) 134 elif new > current: 135 msg = GridTableMessage(self, addmsg, new - current) 136 grid.ProcessTableMessage(msg) 137 self.UpdateValues(grid) 138 grid.EndBatch() 139 140 self._rows = self.GetNumberRows() 141 self._cols = self.GetNumberCols() 142 143 # update the renderers 144 # self._updateColAttrs(grid) 145 # self._updateRowAttrs(grid) too expensive to use on a large grid 146 147 # update the scrollbars and the displayed part of the grid 148 grid.AdjustScrollbars() 149 grid.ForceRefresh() 150 151 def UpdateValues(self, grid): 152 """Update all displayed values""" 153 # This sends an event to the grid table to update all of the values 154 msg = GridTableMessage(self, GRIDTABLE_REQUEST_VIEW_GET_VALUES) 155 grid.ProcessTableMessage(msg) 156 157 def GetAttr88(self, row, col, someExtraParameter): 158 print("Overridden GetAttr ", row, col) 159 """Part of a workaround to avoid use of attributes, queried by _PropertyGrid's IsCurrentCellReadOnly""" 160 # property = self.GetPropertyForCoordinate( row, col ) 161 # object = self.GetObjectForCoordinate( row, col ) 162 # if property.ReadOnly( object ): 163 attr = GridCellAttr() 164 attr.SetReadOnly(1) 165 return attr 166 # return None 167 168 def _updateColAttrs88(self, grid): 169 """ 170 wxGrid -> update the column attributes to add the 171 appropriate renderer given the column name. 172 """ 173 for col, colname in enumerate(self.colnames): 174 attr = GridCellAttr() 175 # attr.SetAlignment(ALIGN_LEFT, ALIGN_CENTRE) 176 if colname in self.renderers: 177 # renderer = self.plugins[colname](self) 178 renderer = self.renderers[colname] 179 # if renderer.colSize: 180 # grid.SetColSize(col, renderer.colSize) 181 # if renderer.rowSize: 182 # grid.SetDefaultRowSize(renderer.rowSize) 183 # attr.SetReadOnly(False) 184 # attr.SetRenderer(renderer) 185 else: 186 renderer = self.renderers["DEFAULT_RENDERER"] # .Clone() 187 188 attr.SetRenderer(renderer) 189 190 """else: 191 #renderer = GridCellFloatRenderer(6,2) 192 #attr.SetReadOnly(True) 193 #attr.SetRenderer(renderer)""" 194 195 if colname in self.editors: 196 editor = self.editors[colname] 197 attr.SetEditor(editor) 198 199 grid.SetColAttr(col, attr) 200 return 201 202 # ------------------------------------------------------------------------------ 203 # code to manipulate the table (non wx related) 204 # ------------------------------------------------------------------------------ 205 206 def AppendRow(self, row): 207 """ Append a tupe containing (name, data) 208 """ 209 name, data = row 210 print("Appending ", name) 211 self._data.append(row) 212 """entry = {} 213 for name in self.colnames: 214 entry[name] = "Appended_%i"%row 215 return""" 216 217 def DeleteCols88(self, cols): 218 """ 219 cols -> delete the columns from the dataset 220 cols hold the column indices 221 """ 222 # we'll cheat here and just remove the name from the 223 # list of column names. The data will remain but 224 # it won't be shown 225 deleteCount = 0 226 cols = cols[:] 227 cols.sort() 228 for i in cols: 229 self.colnames.pop(i - deleteCount) 230 # we need to advance the delete count 231 # to make sure we delete the right columns 232 deleteCount += 1 233 if not len(self.colnames): 234 self.data = [] 235 236 def DeleteRow(self, row): 237 name, data = row 238 print("Deleting ", name) 239 self._data.remove(row) 240 241 def DeleteRows88(self, rows): 242 """ 243 rows -> delete the rows from the dataset 244 rows hold the row indices 245 """ 246 deleteCount = 0 247 rows = rows[:] 248 rows.sort() 249 for i in rows: 250 self._data.pop(i - deleteCount) 251 # we need to advance the delete count 252 # to make sure we delete the right rows 253 deleteCount += 1 254 255 def SortColumn88(self, col): 256 """ 257 to do - never tested 258 tried to rename data to _data and _data to _tmp_data 259 col -> sort the data based on the column indexed by col 260 """ 261 name = self.colnames[col] 262 _tmp_data = [] 263 for row in self._data: 264 rowname, entry = row 265 _tmp_data.append((entry.get(name, None), row)) 266 267 _tmp_data.sort() 268 self._data = [] 269 for sortvalue, row in _tmp_data: 270 self._data.append(row) 271