--- a/controls/DebugVariablePanel/DebugVariableTablePanel.py Fri May 31 14:22:15 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariableTablePanel.py Fri May 31 18:32:51 2013 +0200
@@ -35,9 +35,22 @@
from DebugVariableItem import DebugVariableItem
def GetDebugVariablesTableColnames():
+ Function returning table column header labels + @return: List of labels [col_label,...] return [_("Variable"), _("Value")]
+#------------------------------------------------------------------------------- +# Debug Variable Table Panel +#------------------------------------------------------------------------------- +Class that implements a custom table storing value to display in Debug Variable class DebugVariableTable(CustomTable):
def GetValue(self, row, col):
@@ -69,11 +82,6 @@
return self.data[row].IsForced()
- def IsNumVariable(self, row):
- if row < self.GetNumberRows():
- return self.data[row].IsNumVariable()
def _updateColAttrs(self, grid):
wx.grid.Grid -> update the column attributes to add the
@@ -92,15 +100,26 @@
grid.SetCellTextColour(row, col, wx.BLACK)
grid.SetReadOnly(row, col, True)
self.ResizeRow(grid, row)
- def AppendItem(self, data):
- def InsertItem(self, idx, data):
- self.data.insert(idx, data)
+ def RefreshValues(self, grid): + for col in xrange(self.GetNumberCols()): + colname = self.GetColLabelValue(col, False) + for row in xrange(self.GetNumberRows()): + grid.SetCellValue(row, col, str(self.data[row].GetValue())) + grid.SetCellTextColour(row, col, wx.BLUE) + grid.SetCellTextColour(row, col, wx.BLACK) + def AppendItem(self, item): - def RemoveItem(self, idx):
+ def InsertItem(self, idx, item): + self.data.insert(idx, item) + def RemoveItem(self, item): def MoveItem(self, idx, new_idx):
self.data.insert(new_idx, self.data.pop(idx))
@@ -108,52 +127,109 @@
+#------------------------------------------------------------------------------- +# Debug Variable Table Panel Drop Target +#------------------------------------------------------------------------------- +Class that implements a custom drop target class for Debug Variable Table Panel class DebugVariableTableDropTarget(wx.TextDropTarget):
def __init__(self, parent):
+ @param window: Reference to the Debug Variable Panel wx.TextDropTarget.__init__(self)
self.ParentWindow = parent
+ # Remove reference to Debug Variable Panel def OnDropText(self, x, y, data):
+ Function called when mouse is dragged over Drop Target + @param x: X coordinate of mouse pointer + @param y: Y coordinate of mouse pointer + @param data: Text associated to drag'n drop + if not isinstance(values, TupleType): - message = _("Invalid value \"%s\" for debug variable")%data
- if not isinstance(values, TupleType):
- message = _("Invalid value \"%s\" for debug variable")%data
+ message = _("Invalid value \"%s\" for debug variable") % data wx.CallAfter(self.ShowMessage, message)
- elif values is not None and values[1] == "debug":
+ elif values[1] == "debug": grid = self.ParentWindow.VariablesGrid
+ # Get row where variable was dropped x, y = grid.CalcUnscrolledPosition(x, y)
row = grid.YToRow(y - grid.GetColLabelSize())
+ # If no row found add variable at table end row = self.ParentWindow.Table.GetNumberRows()
+ # Add variable to table self.ParentWindow.InsertValue(values[0], row, force=True)
def ShowMessage(self, message):
- dialog = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ Show error message in Error Dialog + @param message: Error message to display + dialog = wx.MessageDialog(self.ParentWindow,
+#------------------------------------------------------------------------------- +# Debug Variable Table Panel +#------------------------------------------------------------------------------- +Class that implements a panel displaying debug variable values in a table class DebugVariableTablePanel(wx.Panel, DebugViewer):
def __init__(self, parent, producer, window):
+ @param parent: Reference to the parent wx.Window + @param producer: Object receiving debug value and dispatching them to + @param window: Reference to Beremiz frame wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL)
+ # Save Reference to Beremiz frame self.ParentWindow = window
+ # Variable storing flag indicating that variable displayed in table + # received new value and then table need to be refreshed DebugViewer.__init__(self, producer, True)
+ # Construction of window layout by creating controls and sizers main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
@@ -162,17 +238,24 @@
main_sizer.AddSizer(button_sizer, border=5,
flag=wx.ALIGN_RIGHT|wx.ALL)
+ # Creation of buttons for navigating in table for name, bitmap, help in [
("DeleteButton", "remove_element", _("Remove debug variable")),
("UpButton", "up", _("Move debug variable up")),
("DownButton", "down", _("Move debug variable down"))]:
- button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap),
+ button = wx.lib.buttons.GenBitmapButton(self, + bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
button_sizer.AddWindow(button, border=5, flag=wx.LEFT)
- self.VariablesGrid = CustomGrid(self, size=wx.Size(-1, 150), style=wx.VSCROLL)
+ # Creation of grid and associated table + self.VariablesGrid = CustomGrid(self, + size=wx.Size(-1, 150), style=wx.VSCROLL) + # Define grid drop target self.VariablesGrid.SetDropTarget(DebugVariableTableDropTarget(self))
self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK,
self.OnVariablesGridCellRightClick)
@@ -180,12 +263,15 @@
self.OnVariablesGridCellLeftClick)
main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW)
- self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames())
+ self.Table = DebugVariableTable(self, [], + GetDebugVariablesTableColnames()) self.VariablesGrid.SetTable(self.Table)
self.VariablesGrid.SetButtons({"Delete": self.DeleteButton,
"Down": self.DownButton})
+ # Definition of function associated to navigation buttons def _AddVariable(new_row):
return self.VariablesGrid.GetGridCursorRow()
setattr(self.VariablesGrid, "_AddRow", _AddVariable)
@@ -193,7 +279,7 @@
def _DeleteVariable(row):
item = self.Table.GetItem(row)
self.RemoveDataConsumer(item)
- self.Table.RemoveItem(row)
+ self.Table.RemoveItem(item) setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
@@ -205,6 +291,8 @@
setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
+ # Initialization of grid layout self.VariablesGrid.SetRowLabelSize(0)
self.GridColSizes = [200, 100]
@@ -221,35 +309,64 @@
self.SetSizer(main_sizer)
def RefreshNewData(self, *args, **kwargs):
+ Called to refresh Table according to values received by variables + Can receive any parameters (not used here) + # Refresh 'Value' column of table if new data have been received since self.RefreshView(only_values=True)
DebugViewer.RefreshNewData(self, *args, **kwargs)
def RefreshView(self, only_values=False):
+ Function refreshing table layout and values + @param only_values: True if only 'Value' column need to be updated + # Block refresh until table layout and values are completely updated + # Update only 'value' column from table - for col in xrange(self.Table.GetNumberCols()):
- if self.Table.GetColLabelValue(col, False) == "Value":
- for row in xrange(self.Table.GetNumberRows()):
- self.VariablesGrid.SetCellValue(row, col, str(self.Table.GetValueByName(row, "Value")))
- if self.Table.IsForced(row):
- self.VariablesGrid.SetCellTextColour(row, col, wx.BLUE)
- self.VariablesGrid.SetCellTextColour(row, col, wx.BLACK)
+ self.Table.RefreshValues(self.VariablesGrid) + # Update complete table layout refreshing table navigation buttons self.Table.ResetView(self.VariablesGrid)
- self.VariablesGrid.RefreshButtons()
+ self.VariablesGrid.RefreshButtons() - def UnsubscribeObsoleteData(self):
- self.SubscribeAllDataConsumers()
+ Function removing all variables denugged from table + @param only_values: True if only 'Value' column need to be updated + # Unsubscribe all variables debugged + self.UnsubscribeAllDataConsumers() - items = [(idx, item) for idx, item in enumerate(self.Table.GetData())]
- for idx, item in items:
+ self.Table.ResetView(self.VariablesGrid) + self.VariablesGrid.RefreshButtons() + def SubscribeAllDataConsumers(self): + Function refreshing table layout and values + @param only_values: True if only 'Value' column need to be updated + DebugViewer.SubscribeAllDataConsumers(self) + # Navigate through variable displayed in table, removing those that + # doesn't exist anymore in PLC + for item in self.Table.GetData()[:]: iec_path = item.GetVariable()
if self.GetDataType(iec_path) is None:
self.RemoveDataConsumer(item)
@@ -257,80 +374,130 @@
self.AddDataConsumer(iec_path.upper(), item)
item.RefreshVariableType()
- self.Table.ResetView(self.VariablesGrid)
- self.VariablesGrid.RefreshButtons()
- self.UnsubscribeAllDataConsumers()
self.Table.ResetView(self.VariablesGrid)
self.VariablesGrid.RefreshButtons()
- def GetForceVariableMenuFunction(self, iec_path, item):
- iec_type = self.GetDataType(iec_path)
+ def GetForceVariableMenuFunction(self, item): + Function returning callback function for contextual menu 'Force' item + @param item: Debug Variable item where contextual menu was opened + @return: Callback function def ForceVariableFunction(event):
- if iec_type is not None:
- dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
- if dialog.ShowModal() == wx.ID_OK:
- self.ForceDataValue(iec_path.upper(), dialog.GetValue())
+ # Get variable path and data type + iec_path = item.GetVariable() + iec_type = self.GetDataType(iec_path) + # Return immediately if not data type found + # Open dialog for entering value to force variable + dialog = ForceVariableDialog(self, iec_type, str(item.GetValue())) + # If valid value entered, force variable + if dialog.ShowModal() == wx.ID_OK: + self.ForceDataValue(iec_path.upper(), dialog.GetValue()) return ForceVariableFunction
def GetReleaseVariableMenuFunction(self, iec_path):
+ Function returning callback function for contextual menu 'Release' item + @param iec_path: Debug Variable path where contextual menu was opened + @return: Callback function def ReleaseVariableFunction(event):
self.ReleaseDataValue(iec_path)
return ReleaseVariableFunction
def OnVariablesGridCellLeftClick(self, event):
- if event.GetCol() == 0:
- data = wx.TextDataObject(str((self.Table.GetValueByName(row, "Variable"), "debug")))
+ Called when left mouse button is pressed on a table cell + @param event: wx.grid.GridEvent + # Initiate a drag and drop if the cell clicked was in 'Variable' column + if self.Table.GetColLabelValue(event.GetCol(), False) == "Variable": + item = self.Table.GetItem(event.GetRow()) + data = wx.TextDataObject(str((item.GetVariable(), "debug"))) dragSource = wx.DropSource(self.VariablesGrid)
def OnVariablesGridCellRightClick(self, event):
- row, col = event.GetRow(), event.GetCol()
- if self.Table.GetColLabelValue(col, False) == "Value":
- iec_path = self.Table.GetValueByName(row, "Variable").upper()
+ Called when right mouse button is pressed on a table cell + @param event: wx.grid.GridEvent + # Open a contextual menu if the cell clicked was in 'Value' column + if self.Table.GetColLabelValue(event.GetCol(), False) == "Value": + item = self.Table.GetItem(row) + iec_path = item.GetVariable().upper() + # Create contextual menu
- menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Force value"))
- self.Bind(wx.EVT_MENU, self.GetForceVariableMenuFunction(iec_path.upper(), self.Table.GetItem(row)), id=new_id)
+ for text, enable, callback in [ + (_("Force value"), True, + self.GetForceVariableMenuFunction(item)), + # Release menu item is enabled only if variable is forced + (_("Release value"), self.Table.IsForced(row), + self.GetReleaseVariableMenuFunction(iec_path))]: + menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=text) + menu.Enable(new_id, enable) + self.Bind(wx.EVT_MENU, callback, id=new_id)
- menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Release value"))
- self.Bind(wx.EVT_MENU, self.GetReleaseVariableMenuFunction(iec_path.upper()), id=new_id)
- if self.Table.IsForced(row):
- menu.Enable(new_id, True)
- menu.Enable(new_id, False)
+ # Popup contextual menu - def InsertValue(self, iec_path, idx = None, force=False):
+ def InsertValue(self, iec_path, index=None, force=False): + Insert a new variable to debug in table + @param iec_path: Variable path to debug + @param index: Row where insert the variable in table (default None, + insert at last position) + @param force: Force insertion of variable even if not defined in + # Return immediately if variable is already debugged for item in self.Table.GetData():
if iec_path == item.GetVariable():
- idx = self.Table.GetNumberRows()
+ # Insert at last position if index not defined + index = self.Table.GetNumberRows() + # Subscribe variable to producer item = DebugVariableItem(self, iec_path)
result = self.AddDataConsumer(iec_path.upper(), item)
+ # Insert variable in table if subscription done or insertion forced if result is not None or force:
- self.Table.InsertItem(idx, item)
+ self.Table.InsertItem(index, item) def ResetGraphicsValues(self):
+ Called to reset graphics values when PLC is started + (Nothing to do because no graphic values here. Defined for + compatibility with Debug Variable Graphic Panel) \ No newline at end of file