from wxPython.wx import *
from wxPython.grid import *

class GridResizable:
    def __init__(self):
        # The resizable grid needs to remeber how big it was
        # in order to send appropriate events to add and remove
        # columns
        self._cols = self.GetNumberCols()
        self._rows = self.GetNumberRows()
        
    def ResetView(self, grid):
        grid.BeginBatch() 
        for current, new, delmsg, addmsg in [ 
            (self._rows, self.GetNumberRows(), wxGRIDTABLE_NOTIFY_ROWS_DELETED,
            wxGRIDTABLE_NOTIFY_ROWS_APPENDED), 
            (self._cols, self.GetNumberCols(), wxGRIDTABLE_NOTIFY_COLS_DELETED,
            wxGRIDTABLE_NOTIFY_COLS_APPENDED), 
            ]:
            if new < current: 
                msg = wxGridTableMessage(self,delmsg,new,current-new)
                grid.ProcessTableMessage(msg) 
            elif new > current: 
                msg = wxGridTableMessage(self,addmsg,new-current)
                grid.ProcessTableMessage(msg)
        self.UpdateValues(grid) 
        grid.EndBatch()
        self._rows = self.GetNumberRows()
        self._cols = self.GetNumberCols()
        # XXX
        # Okay, this is really stupid, we need to "jiggle" the size
        # to get the scrollbars to recalibrate when the underlying
        # grid changes.
        h,w = grid.GetSize()
        grid.SetSize((h+1, w))
        grid.SetSize((h, w))
        grid.ForceRefresh()
        self.UpdateValues(grid)
        
    def UpdateValues(self, grid): 
        """Update all displayed values without changing the grid size""" 
        msg = wxGridTableMessage(self, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES) 
        grid.ProcessTableMessage(msg)


class RecordGridVirtualTable(wxPyGridTableBase, GridResizable):
    def __init__(self, rownames, colnames, matrix):
        """colnames, rownames, matrix -> initialize the table
        colnames[col] -> the name of the column
        rownames[row] -> the name of the row
        matric[row,col] -> the data value for row, col
        """
        self.colnames = colnames
        self.rownames = rownames
        self.matrix = matrix
        wxPyGridTableBase.__init__(self)
        GridResizable.__init__(self)
    def GetNumberCols(self): return len(self.colnames)
    def GetNumberRows(self): return len(self.rownames)
    def GetColHeaderValue(self, col): return self.colnames[col]
    def GetRowHeaderValue(self, row): return self.rownames[row]
    def GetValue(self, row, col): return self.matrix[row, col]
    def AlterValues(self, rownames, colnames, matrix):
        """rownames, colnames, matrix -> alter values in the table.
        The grid using this table is responsible for redrawing the
        grid"""
        self.colnames = colnames
        self.rownames = rownames
        self.matrix = matrix

class MyGrid(wxGrid):
    def __init__(self, parent, rownames, colnames, matrix):
        wxGrid.__init__(self, parent, -1)
        self.table = RecordGridVirtualTable(rownames, colnames, matrix)
        self.SetTable(self.table)

    def UpdateData(self, rownames, colnames, matrix):
        """change the values in the table"""
        self.table.AlterValues(colnames, rownames, matrix)
        # update the values in the grid.  This takes care
        # of rows and columns being added and removed
        # and redrawing the data in the table.
        self.table.ResetView(self)

if __name__ == "__main__":
    app = wxPySimpleApp(0)
    frame = wxFrame(None, -1, "", size=(300,200))
    frame.Show()
    frame2 = wxFrame(frame, -1, "")
    frame2.Show()
    # make two tables
    rownames = ["This", "Is", "A", "Test", "Of", "The", "Table"]
    colnames = range(0,100)
    data = {}
    for row in range(len(rownames)):
        for col in range(len(colnames)):
            data[row, col] = "Table 1 %s,%s"%(row, col)

    import wx.grid
    filename = wx.grid.__file__
    if filename[-1] == 'c': filename = filename[:-1]
    rownames2 = open(filename).read().split()
    colnames2 = range(0,10)
    data2 = {}
    for row in range(len(rownames2)):
        for col in range(len(colnames2)):
            data2[row, col] = "Table 2 %s,%s"%(row, col)
    
             
    grid = MyGrid(frame, rownames, colnames, data)
    frame.Fit()
    frame.SetSize((500,400))
    button = wxButton(frame2, -1, "Click me to change table values")
    frame2.Fit()
    def launchDlg(evt, frame=frame, grid=grid, rownames=rownames2,
                  colnames=colnames2, data=data2):
        grid.UpdateData(rownames, colnames, data)
        
    EVT_BUTTON(frame2, button.GetId(), launchDlg)
    app.MainLoop()
