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