controls/VariablePanel.py
changeset 586 9aa96a36cf33
parent 580 ad996deb920e
child 591 4d6719c51f05
equal deleted inserted replaced
585:bd8c7a033b17 586:9aa96a36cf33
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
       
     5 #based on the plcopen standard. 
       
     6 #
       
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    21 #You should have received a copy of the GNU General Public
       
    22 #License along with this library; if not, write to the Free Software
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 import os
       
    26 import wx, wx.grid
       
    27 
       
    28 from types import TupleType, StringType, UnicodeType
       
    29 
       
    30 from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS
       
    31 from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD
       
    32 from dialogs import ArrayTypeDialog
       
    33 from CustomGrid import CustomGrid
       
    34 from LocationCellEditor import LocationCellEditor
       
    35 
       
    36 # Compatibility function for wx versions < 2.6
       
    37 def AppendMenu(parent, help, id, kind, text):
       
    38     if wx.VERSION >= (2, 6, 0):
       
    39         parent.Append(help=help, id=id, kind=kind, text=text)
       
    40     else:
       
    41         parent.Append(helpString=help, id=id, kind=kind, item=text)
       
    42 
       
    43 [TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, 
       
    44  INSTANCESTREE, LIBRARYTREE, SCALING
       
    45 ] = range(9)
       
    46 
       
    47 #-------------------------------------------------------------------------------
       
    48 #                            Variables Editor Panel
       
    49 #-------------------------------------------------------------------------------
       
    50 
       
    51 def GetVariableTableColnames(location):
       
    52     _ = lambda x : x
       
    53     if location:
       
    54     	return ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value"), _("Option"), _("Documentation")]
       
    55     return ["#", _("Name"), _("Class"), _("Type"), _("Initial Value"), _("Option"), _("Documentation")]
       
    56 
       
    57 def GetOptions(constant=True, retain=True, non_retain=True):
       
    58     _ = lambda x : x
       
    59     options = [""]
       
    60     if constant:
       
    61         options.append(_("Constant"))
       
    62     if retain:
       
    63         options.append(_("Retain"))
       
    64     if non_retain:
       
    65         options.append(_("Non-Retain"))
       
    66     return options
       
    67 OPTIONS_DICT = dict([(_(option), option) for option in GetOptions()])
       
    68 
       
    69 def GetFilterChoiceTransfer():
       
    70     _ = lambda x : x
       
    71     return {_("All"): _("All"), _("Interface"): _("Interface"), 
       
    72             _("   Input"): _("Input"), _("   Output"): _("Output"), _("   InOut"): _("InOut"), 
       
    73             _("   External"): _("External"), _("Variables"): _("Variables"), _("   Local"): _("Local"),
       
    74             _("   Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")}
       
    75 VARIABLE_CHOICES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().iterkeys()])
       
    76 VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()])
       
    77 
       
    78 CheckOptionForClass = {"Local": lambda x: x,
       
    79                        "Temp": lambda x: "",
       
    80                        "Input": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
       
    81                        "InOut": lambda x: "",
       
    82                        "Output": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
       
    83                        "Global": lambda x: {"Constant": "Constant", "Retain": "Retain"}.get(x, ""),
       
    84                        "External": lambda x: {"Constant": "Constant"}.get(x, "")
       
    85                       }
       
    86 
       
    87 class VariableTable(wx.grid.PyGridTableBase):
       
    88     
       
    89     """
       
    90     A custom wx.grid.Grid Table using user supplied data
       
    91     """
       
    92     def __init__(self, parent, data, colnames):
       
    93         # The base class must be initialized *first*
       
    94         wx.grid.PyGridTableBase.__init__(self)
       
    95         self.data = data
       
    96         self.old_value = None
       
    97         self.colnames = colnames
       
    98         self.Highlights = {}
       
    99         self.Parent = parent
       
   100         # XXX
       
   101         # we need to store the row length and collength to
       
   102         # see if the table has changed size
       
   103         self._rows = self.GetNumberRows()
       
   104         self._cols = self.GetNumberCols()
       
   105     
       
   106     def GetNumberCols(self):
       
   107         return len(self.colnames)
       
   108         
       
   109     def GetNumberRows(self):
       
   110         return len(self.data)
       
   111 
       
   112     def GetColLabelValue(self, col, translate=True):
       
   113         if col < len(self.colnames):
       
   114             if translate:
       
   115                 return _(self.colnames[col])
       
   116             return self.colnames[col]
       
   117 
       
   118     def GetRowLabelValues(self, row, translate=True):
       
   119         return row
       
   120 
       
   121     def GetValue(self, row, col):
       
   122         if row < self.GetNumberRows():
       
   123             if col == 0:
       
   124                 return self.data[row]["Number"]
       
   125             colname = self.GetColLabelValue(col, False)
       
   126             value = self.data[row].get(colname, "")
       
   127             if colname == "Type" and isinstance(value, TupleType):
       
   128                 if value[0] == "array":
       
   129                     return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "..".join(x), value[2])), value[1])
       
   130             if not isinstance(value, (StringType, UnicodeType)):
       
   131                 value = str(value)
       
   132             if colname in ["Class", "Option"]:
       
   133                 return _(value)
       
   134             return value
       
   135     
       
   136     def SetValue(self, row, col, value):
       
   137         if col < len(self.colnames):
       
   138             colname = self.GetColLabelValue(col, False)
       
   139             if colname == "Name":
       
   140                 self.old_value = self.data[row][colname]
       
   141             elif colname == "Class":
       
   142                 value = VARIABLE_CLASSES_DICT[value]
       
   143                 self.SetValueByName(row, "Option", CheckOptionForClass[value](self.GetValueByName(row, "Option")))
       
   144                 if value == "External":
       
   145                     self.SetValueByName(row, "Initial Value", "")
       
   146             elif colname == "Option":
       
   147                 value = OPTIONS_DICT[value]
       
   148             self.data[row][colname] = value
       
   149     
       
   150     def GetValueByName(self, row, colname):
       
   151         if row < self.GetNumberRows():
       
   152             return self.data[row].get(colname)
       
   153 
       
   154     def SetValueByName(self, row, colname, value):
       
   155         if row < self.GetNumberRows():
       
   156             self.data[row][colname] = value
       
   157 
       
   158     def GetOldValue(self):
       
   159         return self.old_value
       
   160     
       
   161     def ResetView(self, grid):
       
   162         """
       
   163         (wx.grid.Grid) -> Reset the grid view.   Call this to
       
   164         update the grid if rows and columns have been added or deleted
       
   165         """
       
   166         grid.BeginBatch()
       
   167         for current, new, delmsg, addmsg in [
       
   168             (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
       
   169             (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
       
   170         ]:
       
   171             if new < current:
       
   172                 msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
       
   173                 grid.ProcessTableMessage(msg)
       
   174             elif new > current:
       
   175                 msg = wx.grid.GridTableMessage(self,addmsg,new-current)
       
   176                 grid.ProcessTableMessage(msg)
       
   177                 self.UpdateValues(grid)
       
   178         grid.EndBatch()
       
   179 
       
   180         self._rows = self.GetNumberRows()
       
   181         self._cols = self.GetNumberCols()
       
   182         # update the column rendering scheme
       
   183         self._updateColAttrs(grid)
       
   184 
       
   185         # update the scrollbars and the displayed part of the grid
       
   186         grid.AdjustScrollbars()
       
   187         grid.ForceRefresh()
       
   188 
       
   189     def UpdateValues(self, grid):
       
   190         """Update all displayed values"""
       
   191         # This sends an event to the grid table to update all of the values
       
   192         msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
       
   193         grid.ProcessTableMessage(msg)
       
   194 
       
   195     def _updateColAttrs(self, grid):
       
   196         """
       
   197         wx.grid.Grid -> update the column attributes to add the
       
   198         appropriate renderer given the column name.
       
   199 
       
   200         Otherwise default to the default renderer.
       
   201         """
       
   202         for row in range(self.GetNumberRows()):
       
   203             var_class = self.GetValueByName(row, "Class")
       
   204             var_type = self.GetValueByName(row, "Type")
       
   205             row_highlights = self.Highlights.get(row, {})
       
   206             for col in range(self.GetNumberCols()):
       
   207                 editor = None
       
   208                 renderer = None
       
   209                 colname = self.GetColLabelValue(col, False)
       
   210                 if colname == "Option":
       
   211                     options = GetOptions(constant = var_class in ["Local", "External", "Global"],
       
   212                                          retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output", "Global"],
       
   213                                          non_retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output"])
       
   214                     if len(options) > 1:
       
   215                         editor = wx.grid.GridCellChoiceEditor()
       
   216                         editor.SetParameters(",".join(map(_, options)))
       
   217                     else:
       
   218                         grid.SetReadOnly(row, col, True)
       
   219                 elif col != 0 and self.GetValueByName(row, "Edit"):
       
   220                     grid.SetReadOnly(row, col, False)
       
   221                     if colname == "Name":
       
   222                         if self.Parent.PouIsUsed and var_class in ["Input", "Output", "InOut"]:
       
   223                             grid.SetReadOnly(row, col, True)
       
   224                         else:
       
   225                             editor = wx.grid.GridCellTextEditor()
       
   226                             renderer = wx.grid.GridCellStringRenderer()
       
   227                     elif colname == "Initial Value":
       
   228                         if var_class != "External":
       
   229                             if self.Parent.Controler.IsEnumeratedType(var_type):
       
   230                                 editor = wx.grid.GridCellChoiceEditor()
       
   231                                 editor.SetParameters(",".join(self.Parent.Controler.GetEnumeratedDataValues(var_type)))
       
   232                             else:
       
   233                                 editor = wx.grid.GridCellTextEditor()
       
   234                             renderer = wx.grid.GridCellStringRenderer()
       
   235                         else:
       
   236                             grid.SetReadOnly(row, col, True)
       
   237                     elif colname == "Location":
       
   238                         if var_class in ["Local", "Global"] and self.Parent.Controler.IsLocatableType(var_type):
       
   239                             editor = LocationCellEditor(self, self.Parent.Controler)
       
   240                             renderer = wx.grid.GridCellStringRenderer()
       
   241                         else:
       
   242                             grid.SetReadOnly(row, col, True)
       
   243                     elif colname == "Class":
       
   244                         if len(self.Parent.ClassList) == 1 or self.Parent.PouIsUsed and var_class in ["Input", "Output", "InOut"]:
       
   245                             grid.SetReadOnly(row, col, True)
       
   246                         else:
       
   247                             editor = wx.grid.GridCellChoiceEditor()
       
   248                             excluded = []
       
   249                             if self.Parent.PouIsUsed:
       
   250                                 excluded.extend(["Input","Output","InOut"])
       
   251                             if self.Parent.IsFunctionBlockType(var_type):
       
   252                                 excluded.extend(["Local","Temp"])
       
   253                             editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded]))
       
   254                 elif colname != "Documentation":
       
   255                     grid.SetReadOnly(row, col, True)
       
   256                 
       
   257                 grid.SetCellEditor(row, col, editor)
       
   258                 grid.SetCellRenderer(row, col, renderer)
       
   259                 
       
   260                 highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
       
   261                 grid.SetCellBackgroundColour(row, col, highlight_colours[0])
       
   262                 grid.SetCellTextColour(row, col, highlight_colours[1])
       
   263             if wx.Platform == '__WXMSW__':
       
   264                 grid.SetRowMinimalHeight(row, 20)
       
   265             else:
       
   266                 grid.SetRowMinimalHeight(row, 28)
       
   267             grid.AutoSizeRow(row, False)
       
   268     
       
   269     def SetData(self, data):
       
   270         self.data = data
       
   271     
       
   272     def GetData(self):
       
   273         return self.data
       
   274     
       
   275     def GetCurrentIndex(self):
       
   276         return self.CurrentIndex
       
   277     
       
   278     def SetCurrentIndex(self, index):
       
   279         self.CurrentIndex = index
       
   280     
       
   281     def AppendRow(self, row_content):
       
   282         self.data.append(row_content)
       
   283 
       
   284     def RemoveRow(self, row_index):
       
   285         self.data.pop(row_index)
       
   286 
       
   287     def GetRow(self, row_index):
       
   288         return self.data[row_index]
       
   289 
       
   290     def Empty(self):
       
   291         self.data = []
       
   292         self.editors = []
       
   293 
       
   294     def AddHighlight(self, infos, highlight_type):
       
   295         row_highlights = self.Highlights.setdefault(infos[0], {})
       
   296         col_highlights = row_highlights.setdefault(infos[1], [])
       
   297         col_highlights.append(highlight_type)
       
   298 
       
   299     def ClearHighlights(self, highlight_type=None):
       
   300         if highlight_type is None:
       
   301             self.Highlights = {}
       
   302         else:
       
   303             for row, row_highlights in self.Highlights.iteritems():
       
   304                 row_items = row_highlights.items()
       
   305                 for col, col_highlights in row_items:
       
   306                     if highlight_type in col_highlights:
       
   307                         col_highlights.remove(highlight_type)
       
   308                     if len(col_highlights) == 0:
       
   309                         row_highlights.pop(col)
       
   310                     
       
   311 
       
   312 class VariableDropTarget(wx.TextDropTarget):
       
   313     '''
       
   314     This allows dragging a variable location from somewhere to the Location
       
   315     column of a variable row.
       
   316     
       
   317     The drag source should be a TextDataObject containing a Python tuple like:
       
   318         ('%ID0.0.0', 'location', 'REAL')
       
   319     
       
   320     c_ext/CFileEditor.py has an example of this (you can drag a C extension
       
   321     variable to the Location column of the variable panel).
       
   322     '''
       
   323     def __init__(self, parent):
       
   324         wx.TextDropTarget.__init__(self)
       
   325         self.ParentWindow = parent
       
   326     
       
   327     def OnDropText(self, x, y, data):
       
   328         x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
       
   329         col = self.ParentWindow.VariablesGrid.XToCol(x)
       
   330         row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize())
       
   331         if col != wx.NOT_FOUND and row != wx.NOT_FOUND:
       
   332             if self.ParentWindow.Table.GetColLabelValue(col, False) != "Location":
       
   333                 return
       
   334             message = None
       
   335             if not self.ParentWindow.Table.GetValueByName(row, "Edit"):
       
   336                 message = _("Can't give a location to a function block instance")
       
   337             elif self.ParentWindow.Table.GetValueByName(row, "Class") not in ["Local", "Global"]:
       
   338                 message = _("Can only give a location to local or global variables")
       
   339             else:
       
   340                 try:
       
   341                     values = eval(data)    
       
   342                 except:
       
   343                     message = _("Invalid value \"%s\" for location")%data
       
   344                     values = None
       
   345                 if not isinstance(values, TupleType):
       
   346                     message = _("Invalid value \"%s\" for location")%data
       
   347                     values = None
       
   348                 if values is not None and values[1] == "location":
       
   349                     location = values[0]
       
   350                     variable_type = self.ParentWindow.Table.GetValueByName(row, "Type")
       
   351                     base_type = self.ParentWindow.Controler.GetBaseType(variable_type)
       
   352                     message = None
       
   353                     if location.startswith("%"):
       
   354                         if base_type != values[2]:
       
   355                             message = _("Incompatible data types between \"%s\" and \"%s\"")%(values[2], variable_type)
       
   356                         else:
       
   357                             self.ParentWindow.Table.SetValue(row, col, location)
       
   358                             self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
       
   359                             self.ParentWindow.SaveValues()
       
   360                     else:
       
   361                         if location[0].isdigit() and base_type != "BOOL":
       
   362                             message = _("Incompatible size of data between \"%s\" and \"BOOL\"")%location
       
   363                         elif location[0] not in LOCATIONDATATYPES:
       
   364                             message = _("Unrecognized data size \"%s\"")%location[0]
       
   365                         elif base_type not in LOCATIONDATATYPES[location[0]]:
       
   366                             message = _("Incompatible size of data between \"%s\" and \"%s\"")%(location, variable_type)
       
   367                         else:
       
   368                             dialog = wx.SingleChoiceDialog(self.ParentWindow, _("Select a variable class:"), _("Variable class"), ["Input", "Output", "Memory"], wx.OK|wx.CANCEL)
       
   369                             if dialog.ShowModal() == wx.ID_OK:
       
   370                                 selected = dialog.GetSelection()
       
   371                                 if selected == 0:
       
   372                                     location = "%I" + location
       
   373                                 elif selected == 1:
       
   374                                     location = "%Q" + location
       
   375                                 else:
       
   376                                     location = "%M" + location
       
   377                                 self.ParentWindow.Table.SetValue(row, col, location)
       
   378                                 self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
       
   379                                 self.ParentWindow.SaveValues()
       
   380                             dialog.Destroy()
       
   381             if message is not None:
       
   382                 wx.CallAfter(self.ShowMessage, message)
       
   383             
       
   384     def ShowMessage(self, message):
       
   385         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
       
   386         message.ShowModal()
       
   387         message.Destroy()
       
   388 
       
   389 [ID_VARIABLEEDITORPANEL, ID_VARIABLEEDITORPANELVARIABLESGRID, 
       
   390  ID_VARIABLEEDITORCONTROLPANEL, ID_VARIABLEEDITORPANELRETURNTYPE, 
       
   391  ID_VARIABLEEDITORPANELCLASSFILTER, ID_VARIABLEEDITORPANELADDBUTTON, 
       
   392  ID_VARIABLEEDITORPANELDELETEBUTTON, ID_VARIABLEEDITORPANELUPBUTTON, 
       
   393  ID_VARIABLEEDITORPANELDOWNBUTTON, ID_VARIABLEEDITORPANELSTATICTEXT1, 
       
   394  ID_VARIABLEEDITORPANELSTATICTEXT2, ID_VARIABLEEDITORPANELSTATICTEXT3,
       
   395 ] = [wx.NewId() for _init_ctrls in range(12)]
       
   396 
       
   397 class VariablePanel(wx.Panel):
       
   398     
       
   399     if wx.VERSION < (2, 6, 0):
       
   400         def Bind(self, event, function, id = None):
       
   401             if id is not None:
       
   402                 event(self, id, function)
       
   403             else:
       
   404                 event(self, function)
       
   405     
       
   406     def _init_coll_MainSizer_Items(self, parent):
       
   407         parent.AddWindow(self.ControlPanel, 0, border=5, flag=wx.GROW|wx.ALL)
       
   408         parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
       
   409         
       
   410     def _init_coll_MainSizer_Growables(self, parent):
       
   411         parent.AddGrowableCol(0)
       
   412         parent.AddGrowableRow(1)
       
   413     
       
   414     def _init_coll_ControlPanelSizer_Items(self, parent):
       
   415         parent.AddWindow(self.staticText1, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
       
   416         parent.AddWindow(self.ReturnType, 0, border=0, flag=0)
       
   417         parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
       
   418         parent.AddWindow(self.ClassFilter, 0, border=0, flag=0)
       
   419         parent.AddWindow(self.AddButton, 0, border=0, flag=0)
       
   420         parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
       
   421         parent.AddWindow(self.UpButton, 0, border=0, flag=0)
       
   422         parent.AddWindow(self.DownButton, 0, border=0, flag=0)
       
   423         
       
   424     def _init_coll_ControlPanelSizer_Growables(self, parent):
       
   425         parent.AddGrowableCol(3)
       
   426         parent.AddGrowableRow(0)
       
   427 
       
   428     def _init_sizers(self):
       
   429         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
       
   430         self.ControlPanelSizer = wx.FlexGridSizer(cols=8, hgap=5, rows=1, vgap=5)
       
   431         
       
   432         self._init_coll_MainSizer_Items(self.MainSizer)
       
   433         self._init_coll_MainSizer_Growables(self.MainSizer)
       
   434         self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer)
       
   435         self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer)
       
   436         
       
   437         self.ControlPanel.SetSizer(self.ControlPanelSizer)
       
   438         self.SetSizer(self.MainSizer)
       
   439     
       
   440     def _init_ctrls(self, prnt):
       
   441         wx.Panel.__init__(self, id=ID_VARIABLEEDITORPANEL,
       
   442               name='VariableEditorPanel', parent=prnt, pos=wx.Point(0, 0),
       
   443               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
   444 
       
   445         self.VariablesGrid = CustomGrid(id=ID_VARIABLEEDITORPANELVARIABLESGRID,
       
   446               name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
       
   447               size=wx.Size(0, 0), style=wx.VSCROLL)
       
   448         self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
       
   449               'Sans'))
       
   450         self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
       
   451               False, 'Sans'))
       
   452         self.VariablesGrid.SetSelectionBackground(wx.WHITE)
       
   453         self.VariablesGrid.SetSelectionForeground(wx.BLACK)
       
   454         if wx.VERSION >= (2, 6, 0):
       
   455             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
       
   456             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
       
   457             self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
       
   458         else:
       
   459             wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange)
       
   460             wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
       
   461             wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown)
       
   462         
       
   463         self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL,
       
   464               name='ControlPanel', parent=self, pos=wx.Point(0, 0),
       
   465               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
   466         self.ControlPanel.SetScrollRate(10, 0)
       
   467         
       
   468         self.staticText1 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT1,
       
   469               label=_('Return Type:'), name='staticText1', parent=self.ControlPanel,
       
   470               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   471 
       
   472         self.ReturnType = wx.ComboBox(id=ID_VARIABLEEDITORPANELRETURNTYPE,
       
   473               name='ReturnType', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
   474               size=wx.Size(145, 28), style=wx.CB_READONLY)
       
   475         self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, id=ID_VARIABLEEDITORPANELRETURNTYPE)
       
   476 
       
   477         self.staticText2 = wx.StaticText(id=ID_VARIABLEEDITORPANELSTATICTEXT2,
       
   478               label=_('Class Filter:'), name='staticText2', parent=self.ControlPanel,
       
   479               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   480 
       
   481         self.ClassFilter = wx.ComboBox(id=ID_VARIABLEEDITORPANELCLASSFILTER,
       
   482               name='ClassFilter', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
   483               size=wx.Size(145, 28), style=wx.CB_READONLY)
       
   484         self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, id=ID_VARIABLEEDITORPANELCLASSFILTER)
       
   485 
       
   486         self.AddButton = wx.Button(id=ID_VARIABLEEDITORPANELADDBUTTON, label=_('Add'),
       
   487               name='AddButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
   488               size=wx.DefaultSize, style=0)
       
   489         
       
   490         self.DeleteButton = wx.Button(id=ID_VARIABLEEDITORPANELDELETEBUTTON, label=_('Delete'),
       
   491               name='DeleteButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
   492               size=wx.DefaultSize, style=0)
       
   493         
       
   494         self.UpButton = wx.Button(id=ID_VARIABLEEDITORPANELUPBUTTON, label='^',
       
   495               name='UpButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
   496               size=wx.Size(28, 28), style=0)
       
   497         
       
   498         self.DownButton = wx.Button(id=ID_VARIABLEEDITORPANELDOWNBUTTON, label='v',
       
   499               name='DownButton', parent=self.ControlPanel, pos=wx.Point(0, 0),
       
   500               size=wx.Size(28, 28), style=0)
       
   501         
       
   502         self._init_sizers()
       
   503 
       
   504     def __init__(self, parent, window, controler, element_type):
       
   505         self._init_ctrls(parent)
       
   506         self.ParentWindow = window
       
   507         self.Controler = controler
       
   508         self.ElementType = element_type
       
   509         
       
   510         self.RefreshHighlightsTimer = wx.Timer(self, -1)
       
   511         self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer)
       
   512         
       
   513         self.Filter = "All"
       
   514         self.FilterChoices = []
       
   515         self.FilterChoiceTransfer = GetFilterChoiceTransfer()
       
   516         
       
   517         self.DefaultValue = {   "Name" : "", "Class" : "", "Type" : "INT", "Location" : "",
       
   518                                 "Initial Value" : "", "Option" : "",
       
   519                                 "Documentation" : "", "Edit" : True
       
   520                             }
       
   521 
       
   522         if element_type in ["config", "resource"]:
       
   523             self.DefaultTypes = {"All" : "Global"}
       
   524         else:
       
   525             self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"}
       
   526 
       
   527         if element_type in ["config", "resource"] \
       
   528         or element_type in ["program", "transition", "action"]:
       
   529             # this is an element that can have located variables
       
   530             self.Table = VariableTable(self, [], GetVariableTableColnames(True))
       
   531 
       
   532             if element_type in ["config", "resource"]:
       
   533                 self.FilterChoices = ["All", "Global"]#,"Access"]
       
   534             else:
       
   535                 self.FilterChoices = ["All",
       
   536                                         "Interface", "   Input", "   Output", "   InOut", "   External",
       
   537                                         "Variables", "   Local", "   Temp"]#,"Access"]
       
   538 
       
   539             # these condense the ColAlignements list
       
   540             l = wx.ALIGN_LEFT
       
   541             c = wx.ALIGN_CENTER 
       
   542 
       
   543             #                      Num  Name    Class   Type    Loc     Init    Option   Doc
       
   544             self.ColSizes       = [40,  80,     70,     80,     80,     80,     100,     80]
       
   545             self.ColAlignements = [c,   l,      l,      l,      l,      l,      l,       l]
       
   546 
       
   547         else:
       
   548             # this is an element that cannot have located variables
       
   549             self.Table = VariableTable(self, [], GetVariableTableColnames(False))
       
   550 
       
   551             if element_type == "function":
       
   552                 self.FilterChoices = ["All",
       
   553                                         "Interface", "   Input", "   Output", "   InOut",
       
   554                                         "Variables", "   Local"]
       
   555             else:
       
   556                 self.FilterChoices = ["All",
       
   557                                         "Interface", "   Input", "   Output", "   InOut", "   External",
       
   558                                         "Variables", "   Local", "   Temp"]
       
   559 
       
   560             # these condense the ColAlignements list
       
   561             l = wx.ALIGN_LEFT
       
   562             c = wx.ALIGN_CENTER 
       
   563 
       
   564             #                      Num  Name    Class   Type    Init    Option   Doc
       
   565             self.ColSizes       = [40,  80,     70,     80,     80,     100,     160]
       
   566             self.ColAlignements = [c,   l,      l,      l,      l,      l,       l]
       
   567 
       
   568         for choice in self.FilterChoices:
       
   569             self.ClassFilter.Append(_(choice))
       
   570 
       
   571         reverse_transfer = {}
       
   572         for filter, choice in self.FilterChoiceTransfer.items():
       
   573             reverse_transfer[choice] = filter
       
   574         self.ClassFilter.SetStringSelection(_(reverse_transfer[self.Filter]))
       
   575         self.RefreshTypeList()
       
   576 
       
   577         self.VariablesGrid.SetTable(self.Table)
       
   578         self.VariablesGrid.SetButtons({"Add": self.AddButton,
       
   579                                        "Delete": self.DeleteButton,
       
   580                                        "Up": self.UpButton,
       
   581                                        "Down": self.DownButton})
       
   582         
       
   583         def _AddVariable(new_row):
       
   584             if not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"]:
       
   585                 row_content = self.DefaultValue.copy()
       
   586                 if self.Filter in self.DefaultTypes:
       
   587                     row_content["Class"] = self.DefaultTypes[self.Filter]
       
   588                 else:
       
   589                     row_content["Class"] = self.Filter
       
   590                 if self.Filter == "All" and len(self.Values) > 0:
       
   591                     self.Values.insert(new_row, row_content)
       
   592                 else:
       
   593                     self.Values.append(row_content)
       
   594                     new_row = self.Table.GetNumberRows()
       
   595                 self.SaveValues()
       
   596                 self.RefreshValues()
       
   597                 return new_row
       
   598             return self.VariablesGrid.GetGridCursorRow()
       
   599         setattr(self.VariablesGrid, "_AddRow", _AddVariable)
       
   600         
       
   601         def _DeleteVariable(row):
       
   602             if (self.Table.GetValueByName(row, "Edit") and 
       
   603                 (not self.PouIsUsed or self.Table.GetValueByName(row, "Class") not in ["Input", "Output", "InOut"])):
       
   604                 self.Values.remove(self.Table.GetRow(row))
       
   605                 self.SaveValues()
       
   606                 self.RefreshValues()
       
   607         setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
       
   608             
       
   609         def _MoveVariable(row, move):
       
   610             if (self.Filter == "All" and 
       
   611                 (not self.PouIsUsed or self.Table.GetValueByName(row, "Class") not in ["Input", "Output", "InOut"])):
       
   612                 new_row = max(0, min(row + move, len(self.Values) - 1))
       
   613                 if new_row != row:
       
   614                     self.Values.insert(new_row, self.Values.pop(row))
       
   615                     self.SaveValues()
       
   616                     self.RefreshValues()
       
   617                 return new_row
       
   618             return row
       
   619         setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
       
   620         
       
   621         def _RefreshButtons():
       
   622             table_length = len(self.Table.data)
       
   623             row_class = None
       
   624             row_edit = True
       
   625             row = 0
       
   626             if table_length > 0:
       
   627                 row = self.VariablesGrid.GetGridCursorRow()
       
   628                 row_edit = self.Table.GetValueByName(row, "Edit")
       
   629                 if self.PouIsUsed:
       
   630                     row_class = self.Table.GetValueByName(row, "Class")
       
   631             self.AddButton.Enable(not self.PouIsUsed or self.Filter not in ["Interface", "Input", "Output", "InOut"])
       
   632             self.DeleteButton.Enable(table_length > 0 and row_edit and row_class not in ["Input", "Output", "InOut"])
       
   633             self.UpButton.Enable(table_length > 0 and row > 0 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"])
       
   634             self.DownButton.Enable(table_length > 0 and row < table_length - 1 and self.Filter == "All" and row_class not in ["Input", "Output", "InOut"])
       
   635         setattr(self.VariablesGrid, "RefreshButtons", _RefreshButtons)
       
   636         
       
   637         self.VariablesGrid.SetRowLabelSize(0)
       
   638         for col in range(self.Table.GetNumberCols()):
       
   639             attr = wx.grid.GridCellAttr()
       
   640             attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
       
   641             self.VariablesGrid.SetColAttr(col, attr)
       
   642             self.VariablesGrid.SetColMinimalWidth(col, self.ColSizes[col])
       
   643             self.VariablesGrid.AutoSizeColumn(col, False)
       
   644     
       
   645     def __del__(self):
       
   646         self.RefreshHighlightsTimer.Stop()
       
   647     
       
   648     def SetTagName(self, tagname):
       
   649         self.TagName = tagname
       
   650     
       
   651     def IsFunctionBlockType(self, name):
       
   652         bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
       
   653         pouname, poutype = self.Controler.GetEditedElementType(self.TagName)
       
   654         if poutype != "function" and bodytype in ["ST", "IL"]:
       
   655             return False
       
   656         else:
       
   657             return name in self.Controler.GetFunctionBlockTypes(self.TagName)
       
   658     
       
   659     def RefreshView(self):
       
   660         self.PouNames = self.Controler.GetProjectPouNames()
       
   661         
       
   662         words = self.TagName.split("::")
       
   663         if self.ElementType == "config":
       
   664             self.PouIsUsed = False
       
   665             returnType = None
       
   666             self.Values = self.Controler.GetConfigurationGlobalVars(words[1])
       
   667         elif self.ElementType == "resource":
       
   668             self.PouIsUsed = False
       
   669             returnType = None
       
   670             self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2])
       
   671         else:
       
   672             if self.ElementType == "function":
       
   673                 self.ReturnType.Clear()
       
   674                 for base_type in self.Controler.GetDataTypes(self.TagName, True):
       
   675                     self.ReturnType.Append(base_type)
       
   676                 returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName)
       
   677             else:
       
   678                 returnType = None
       
   679             self.PouIsUsed = self.Controler.PouIsUsed(words[1])
       
   680             self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName)
       
   681         
       
   682         if returnType is not None:
       
   683             self.ReturnType.SetStringSelection(returnType)
       
   684             self.ReturnType.Enable(True)
       
   685             self.staticText1.Show()
       
   686             self.ReturnType.Show()
       
   687         else:
       
   688             self.ReturnType.Enable(False)
       
   689             self.staticText1.Hide()
       
   690             self.ReturnType.Hide()
       
   691         
       
   692         self.RefreshValues()
       
   693         self.VariablesGrid.RefreshButtons()
       
   694     
       
   695     def OnReturnTypeChanged(self, event):
       
   696         words = self.TagName.split("::")
       
   697         self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
       
   698         self.Controler.BufferProject()
       
   699         self.ParentWindow.RefreshView(variablepanel = False)
       
   700         self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
       
   701         event.Skip()
       
   702     
       
   703     def OnClassFilter(self, event):
       
   704         self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]]
       
   705         self.RefreshTypeList()
       
   706         self.RefreshValues()
       
   707         self.VariablesGrid.RefreshButtons()
       
   708         event.Skip()
       
   709 
       
   710     def RefreshTypeList(self):
       
   711         if self.Filter == "All":
       
   712             self.ClassList = [self.FilterChoiceTransfer[choice] for choice in self.FilterChoices if self.FilterChoiceTransfer[choice] not in ["All","Interface","Variables"]]
       
   713         elif self.Filter == "Interface":
       
   714             self.ClassList = ["Input","Output","InOut","External"]
       
   715         elif self.Filter == "Variables":
       
   716             self.ClassList = ["Local","Temp"]
       
   717         else:
       
   718             self.ClassList = [self.Filter]
       
   719 
       
   720     def OnVariablesGridCellChange(self, event):
       
   721         row, col = event.GetRow(), event.GetCol()
       
   722         colname = self.Table.GetColLabelValue(col, False)
       
   723         value = self.Table.GetValue(row, col)
       
   724 
       
   725         if colname == "Name" and value != "":
       
   726             if not TestIdentifier(value):
       
   727                 message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
   728                 message.ShowModal()
       
   729                 message.Destroy()
       
   730                 event.Veto()
       
   731             elif value.upper() in IEC_KEYWORDS:
       
   732                 message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
   733                 message.ShowModal()
       
   734                 message.Destroy()
       
   735                 event.Veto()
       
   736             elif value.upper() in self.PouNames:
       
   737                 message = wx.MessageDialog(self, _("A POU named \"%s\" already exists!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
   738                 message.ShowModal()
       
   739                 message.Destroy()
       
   740                 event.Veto()
       
   741             elif value.upper() in [var["Name"].upper() for var in self.Values if var != self.Table.data[row]]:
       
   742                 message = wx.MessageDialog(self, _("A variable with \"%s\" as name already exists in this pou!")%value, _("Error"), wx.OK|wx.ICON_ERROR)
       
   743                 message.ShowModal()
       
   744                 message.Destroy()
       
   745                 event.Veto()
       
   746             else:
       
   747                 self.SaveValues(False)
       
   748                 old_value = self.Table.GetOldValue()
       
   749                 if old_value != "":
       
   750                     self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
       
   751                 self.Controler.BufferProject()
       
   752                 self.ParentWindow.RefreshView(variablepanel = False)
       
   753                 self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
       
   754                 event.Skip()
       
   755         else:
       
   756             self.SaveValues()
       
   757             if colname == "Class":
       
   758                 self.ParentWindow.RefreshView(variablepanel = False)
       
   759             event.Skip()
       
   760     
       
   761     def OnVariablesGridEditorShown(self, event):
       
   762         row, col = event.GetRow(), event.GetCol() 
       
   763 
       
   764         label_value = self.Table.GetColLabelValue(col)
       
   765         if label_value == "Type":
       
   766             type_menu = wx.Menu(title='')   # the root menu
       
   767 
       
   768             # build a submenu containing standard IEC types
       
   769             base_menu = wx.Menu(title='')
       
   770             for base_type in self.Controler.GetBaseTypes():
       
   771                 new_id = wx.NewId()
       
   772                 AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type)
       
   773                 self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id)
       
   774 
       
   775             type_menu.AppendMenu(wx.NewId(), _("Base Types"), base_menu)
       
   776 
       
   777             # build a submenu containing user-defined types
       
   778             datatype_menu = wx.Menu(title='')
       
   779             
       
   780             # TODO : remove complextypes argument when matiec can manage complex types in pou interface
       
   781             datatypes = self.Controler.GetDataTypes(basetypes = False)
       
   782             for datatype in datatypes:
       
   783                 new_id = wx.NewId()
       
   784                 AppendMenu(datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
       
   785                 self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
       
   786 
       
   787             type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu)
       
   788 
       
   789             # build a submenu containing function block types
       
   790             bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
       
   791             pouname, poutype = self.Controler.GetEditedElementType(self.TagName)
       
   792             classtype = self.Table.GetValueByName(row, "Class")
       
   793             
       
   794             new_id = wx.NewId()
       
   795             AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array"))
       
   796             self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id)
       
   797             
       
   798             if classtype in ["Input", "Output", "InOut", "External", "Global"] or \
       
   799             poutype != "function" and bodytype in ["ST", "IL"]:
       
   800                 functionblock_menu = wx.Menu(title='')
       
   801                 fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName)
       
   802                 for functionblock_type in fbtypes:
       
   803                     new_id = wx.NewId()
       
   804                     AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type)
       
   805                     self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id)
       
   806 
       
   807                 type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu)
       
   808 
       
   809             rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col))
       
   810             corner_x = rect.x + rect.width
       
   811             corner_y = rect.y + self.VariablesGrid.GetColLabelSize()
       
   812 
       
   813             # pop up this new menu
       
   814             self.VariablesGrid.PopupMenuXY(type_menu, corner_x, corner_y)
       
   815             event.Veto()
       
   816         else:
       
   817             event.Skip()
       
   818     
       
   819     def GetVariableTypeFunction(self, base_type):
       
   820         def VariableTypeFunction(event):
       
   821             row = self.VariablesGrid.GetGridCursorRow()
       
   822             self.Table.SetValueByName(row, "Type", base_type)
       
   823             self.Table.ResetView(self.VariablesGrid)
       
   824             self.SaveValues(False)
       
   825             self.ParentWindow.RefreshView(variablepanel = False)
       
   826             self.Controler.BufferProject()
       
   827             self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
       
   828         return VariableTypeFunction
       
   829     
       
   830     def VariableArrayTypeFunction(self, event):
       
   831         row = self.VariablesGrid.GetGridCursorRow()
       
   832         dialog = ArrayTypeDialog(self, 
       
   833                                  self.Controler.GetDataTypes(self.TagName), 
       
   834                                  self.Table.GetValueByName(row, "Type"))
       
   835         if dialog.ShowModal() == wx.ID_OK:
       
   836             self.Table.SetValueByName(row, "Type", dialog.GetValue())
       
   837             self.Table.ResetView(self.VariablesGrid)
       
   838             self.SaveValues(False)
       
   839             self.ParentWindow.RefreshView(variablepanel = False)
       
   840             self.Controler.BufferProject()
       
   841             self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)
       
   842         dialog.Destroy()
       
   843     
       
   844     def OnVariablesGridCellLeftClick(self, event):
       
   845         row = event.GetRow()
       
   846         if event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit"):
       
   847             row = event.GetRow()
       
   848             var_name = self.Table.GetValueByName(row, "Name")
       
   849             var_class = self.Table.GetValueByName(row, "Class")
       
   850             var_type = self.Table.GetValueByName(row, "Type")
       
   851             data = wx.TextDataObject(str((var_name, var_class, var_type, self.TagName)))
       
   852             dragSource = wx.DropSource(self.VariablesGrid)
       
   853             dragSource.SetData(data)
       
   854             dragSource.DoDragDrop()
       
   855         event.Skip()
       
   856     
       
   857     def RefreshValues(self):
       
   858         data = []
       
   859         for num, variable in enumerate(self.Values):
       
   860             if variable["Class"] in self.ClassList:
       
   861                 variable["Number"] = num + 1
       
   862                 data.append(variable)
       
   863         self.Table.SetData(data)
       
   864         self.Table.ResetView(self.VariablesGrid)
       
   865             
       
   866     def SaveValues(self, buffer = True):
       
   867         words = self.TagName.split("::")
       
   868         if self.ElementType == "config":
       
   869             self.Controler.SetConfigurationGlobalVars(words[1], self.Values)
       
   870         elif self.ElementType == "resource":
       
   871             self.Controler.SetConfigurationResourceGlobalVars(words[1], words[2], self.Values)
       
   872         else:
       
   873             if self.ReturnType.IsEnabled():
       
   874                 self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
       
   875             self.Controler.SetPouInterfaceVars(words[1], self.Values)
       
   876         if buffer:
       
   877             self.Controler.BufferProject()
       
   878             self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE)            
       
   879 
       
   880 #-------------------------------------------------------------------------------
       
   881 #                        Highlights showing functions
       
   882 #-------------------------------------------------------------------------------
       
   883 
       
   884     def OnRefreshHighlightsTimer(self, event):
       
   885         self.Table.ResetView(self.VariablesGrid)
       
   886         event.Skip()
       
   887 
       
   888     def AddVariableHighlight(self, infos, highlight_type):
       
   889         if isinstance(infos[0], TupleType):
       
   890             for i in xrange(*infos[0]):
       
   891                 self.Table.AddHighlight((i,) + infos[1:], highlight_type)
       
   892         else:
       
   893             self.Table.AddHighlight(infos, highlight_type)
       
   894         self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
       
   895 
       
   896     def ClearHighlights(self, highlight_type=None):
       
   897         self.Table.ClearHighlights(highlight_type)
       
   898         self.Table.ResetView(self.VariablesGrid)