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