laurent@684: #!/usr/bin/env python laurent@684: # -*- coding: utf-8 -*- laurent@684: laurent@604: #This library is free software; you can redistribute it and/or laurent@604: #modify it under the terms of the GNU General Public laurent@604: #License as published by the Free Software Foundation; either laurent@604: #version 2.1 of the License, or (at your option) any later version. laurent@604: # laurent@604: #This library is distributed in the hope that it will be useful, laurent@604: #but WITHOUT ANY WARRANTY; without even the implied warranty of laurent@604: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU laurent@604: #General Public License for more details. laurent@604: # laurent@604: #You should have received a copy of the GNU General Public laurent@604: #License along with this library; if not, write to the Free Software laurent@604: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA laurent@604: laurent@604: import wx laurent@604: import wx.grid laurent@604: laurent@604: class CustomTable(wx.grid.PyGridTableBase): laurent@604: laurent@604: """ laurent@604: A custom wx.grid.Grid Table using user supplied data laurent@604: """ laurent@604: def __init__(self, parent, data, colnames): laurent@604: # The base class must be initialized *first* laurent@604: wx.grid.PyGridTableBase.__init__(self) laurent@604: self.data = data laurent@604: self.colnames = colnames laurent@604: self.Highlights = {} laurent@604: self.Parent = parent laurent@604: # XXX laurent@604: # we need to store the row length and collength to laurent@604: # see if the table has changed size laurent@604: self._rows = self.GetNumberRows() laurent@604: self._cols = self.GetNumberCols() laurent@604: laurent@604: def GetNumberCols(self): laurent@604: return len(self.colnames) laurent@604: laurent@604: def GetNumberRows(self): laurent@604: return len(self.data) laurent@604: laurent@604: def GetColLabelValue(self, col, translate=True): laurent@604: if col < len(self.colnames): laurent@604: if translate: laurent@604: return _(self.colnames[col]) laurent@604: return self.colnames[col] laurent@604: laurent@604: def GetRowLabelValue(self, row, translate=True): laurent@604: return row laurent@604: laurent@604: def GetValue(self, row, col): laurent@604: if row < self.GetNumberRows(): laurent@604: return self.data[row].get(self.GetColLabelValue(col, False), "") laurent@604: laurent@604: def SetValue(self, row, col, value): laurent@604: if col < len(self.colnames): laurent@604: self.data[row][self.GetColLabelValue(col, False)] = value laurent@604: laurent@604: def GetValueByName(self, row, colname): laurent@604: if row < self.GetNumberRows(): laurent@604: return self.data[row].get(colname) laurent@604: laurent@604: def SetValueByName(self, row, colname, value): laurent@604: if row < self.GetNumberRows(): laurent@604: self.data[row][colname] = value laurent@604: laurent@604: def ResetView(self, grid): laurent@604: """ laurent@604: (wx.grid.Grid) -> Reset the grid view. Call this to laurent@604: update the grid if rows and columns have been added or deleted laurent@604: """ laurent@662: grid.CloseEditControl() laurent@604: grid.BeginBatch() laurent@604: for current, new, delmsg, addmsg in [ laurent@604: (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED), laurent@604: (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED), laurent@604: ]: laurent@604: if new < current: laurent@604: msg = wx.grid.GridTableMessage(self,delmsg,new,current-new) laurent@604: grid.ProcessTableMessage(msg) laurent@604: elif new > current: laurent@604: msg = wx.grid.GridTableMessage(self,addmsg,new-current) laurent@604: grid.ProcessTableMessage(msg) laurent@604: self.UpdateValues(grid) laurent@604: grid.EndBatch() laurent@604: laurent@604: self._rows = self.GetNumberRows() laurent@604: self._cols = self.GetNumberCols() laurent@604: # update the column rendering scheme laurent@604: self._updateColAttrs(grid) laurent@604: laurent@604: # update the scrollbars and the displayed part of the grid laurent@604: grid.AdjustScrollbars() laurent@604: grid.ForceRefresh() laurent@604: laurent@604: def UpdateValues(self, grid): laurent@604: """Update all displayed values""" laurent@604: # This sends an event to the grid table to update all of the values laurent@604: msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES) laurent@604: grid.ProcessTableMessage(msg) laurent@604: laurent@604: def _updateColAttrs(self, grid): laurent@604: """ laurent@604: wx.grid.Grid -> update the column attributes to add the laurent@604: appropriate renderer given the column name. laurent@604: laurent@604: Otherwise default to the default renderer. laurent@604: """ laurent@604: for row in range(self.GetNumberRows()): laurent@604: row_highlights = self.Highlights.get(row, {}) laurent@604: for col in range(self.GetNumberCols()): laurent@606: colname = self.GetColLabelValue(col, False) laurent@606: laurent@604: grid.SetReadOnly(row, col, True) laurent@604: grid.SetCellEditor(row, col, None) laurent@604: grid.SetCellRenderer(row, col, None) laurent@604: laurent@604: highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1] laurent@604: grid.SetCellBackgroundColour(row, col, highlight_colours[0]) laurent@604: grid.SetCellTextColour(row, col, highlight_colours[1]) laurent@604: self.ResizeRow(grid, row) laurent@604: laurent@604: def ResizeRow(self, grid, row): laurent@604: if wx.Platform == '__WXMSW__': laurent@604: grid.SetRowMinimalHeight(row, 20) laurent@604: else: laurent@604: grid.SetRowMinimalHeight(row, 28) laurent@604: grid.AutoSizeRow(row, False) laurent@604: laurent@604: def SetData(self, data): laurent@604: self.data = data laurent@604: laurent@604: def GetData(self): laurent@604: return self.data laurent@604: laurent@604: def GetCurrentIndex(self): laurent@604: return self.CurrentIndex laurent@604: laurent@604: def SetCurrentIndex(self, index): laurent@604: self.CurrentIndex = index laurent@604: laurent@604: def AppendRow(self, row_content): laurent@604: self.data.append(row_content) laurent@604: laurent@604: def InsertRow(self, index, row_content): laurent@604: self.data.insert(index, row_content) laurent@604: laurent@604: def MoveRow(self, row_index, move): laurent@604: new_index = max(0, min(row_index + move, len(self.data) - 1)) laurent@604: if new_index != row_index: laurent@604: self.data.insert(new_index, self.data.pop(row_index)) laurent@604: return new_index laurent@604: laurent@604: def RemoveRow(self, row_index): laurent@604: self.data.pop(row_index) laurent@604: laurent@604: def GetRow(self, row_index): laurent@604: return self.data[row_index] laurent@604: laurent@604: def Empty(self): laurent@604: self.data = [] laurent@604: laurent@604: def AddHighlight(self, infos, highlight_type): laurent@604: row_highlights = self.Highlights.setdefault(infos[0], {}) laurent@604: col_highlights = row_highlights.setdefault(infos[1], []) laurent@604: col_highlights.append(highlight_type) laurent@604: Laurent@738: def RemoveHighlight(self, infos, highlight_type): Laurent@738: row_highlights = self.Highlights.get(infos[0]) Laurent@738: if row_highlights is not None: Laurent@738: col_highlights = row_highlights.get(infos[1]) Laurent@738: if col_highlights is not None and highlight_type in col_highlights: Laurent@738: col_highlights.remove(highlight_type) Laurent@738: if len(col_highlights) == 0: Laurent@738: row_highlights.pop(infos[1]) Laurent@738: laurent@604: def ClearHighlights(self, highlight_type=None): laurent@604: if highlight_type is None: laurent@604: self.Highlights = {} laurent@604: else: laurent@604: for row, row_highlights in self.Highlights.iteritems(): laurent@604: row_items = row_highlights.items() laurent@604: for col, col_highlights in row_items: laurent@604: if highlight_type in col_highlights: laurent@604: col_highlights.remove(highlight_type) laurent@604: if len(col_highlights) == 0: laurent@604: row_highlights.pop(col)