etherlab/ConfigEditor.py
changeset 2355 fec77f2b9e07
parent 2354 9460872f1440
child 2356 c26e0c66d8d5
equal deleted inserted replaced
2354:9460872f1440 2355:fec77f2b9e07
    65 ETHERCAT_INDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,4})$")
    65 ETHERCAT_INDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,4})$")
    66 ETHERCAT_SUBINDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,2})$")
    66 ETHERCAT_SUBINDEX_MODEL = re.compile("#x([0-9a-fA-F]{0,2})$")
    67 LOCATION_MODEL = re.compile("(?:%[IQM](?:[XBWLD]?([0-9]+(?:\.[0-9]+)*)))$")
    67 LOCATION_MODEL = re.compile("(?:%[IQM](?:[XBWLD]?([0-9]+(?:\.[0-9]+)*)))$")
    68 
    68 
    69 class NodeVariablesSizer(wx.FlexGridSizer):
    69 class NodeVariablesSizer(wx.FlexGridSizer):
    70     
    70 
    71     def __init__(self, parent, controler, position_column=False):
    71     def __init__(self, parent, controler, position_column=False):
    72         wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=2, vgap=5)
    72         wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=2, vgap=5)
    73         self.AddGrowableCol(0)
    73         self.AddGrowableCol(0)
    74         self.AddGrowableRow(1)
    74         self.AddGrowableRow(1)
    75         
    75 
    76         self.Controler = controler
    76         self.Controler = controler
    77         self.PositionColumn = position_column
    77         self.PositionColumn = position_column
    78         
    78 
    79         self.VariablesFilter = wx.ComboBox(parent, style=wx.TE_PROCESS_ENTER)
    79         self.VariablesFilter = wx.ComboBox(parent, style=wx.TE_PROCESS_ENTER)
    80         self.VariablesFilter.Bind(wx.EVT_COMBOBOX, self.OnVariablesFilterChanged)
    80         self.VariablesFilter.Bind(wx.EVT_COMBOBOX, self.OnVariablesFilterChanged)
    81         self.VariablesFilter.Bind(wx.EVT_TEXT_ENTER, self.OnVariablesFilterChanged)
    81         self.VariablesFilter.Bind(wx.EVT_TEXT_ENTER, self.OnVariablesFilterChanged)
    82         self.VariablesFilter.Bind(wx.EVT_CHAR, self.OnVariablesFilterKeyDown)
    82         self.VariablesFilter.Bind(wx.EVT_CHAR, self.OnVariablesFilterKeyDown)
    83         self.AddWindow(self.VariablesFilter, flag=wx.GROW)
    83         self.AddWindow(self.VariablesFilter, flag=wx.GROW)
    84         
    84 
    85         self.VariablesGrid = wx.gizmos.TreeListCtrl(parent, 
    85         self.VariablesGrid = wx.gizmos.TreeListCtrl(parent,
    86                 style=wx.TR_DEFAULT_STYLE |
    86                 style=wx.TR_DEFAULT_STYLE |
    87                       wx.TR_ROW_LINES |
    87                       wx.TR_ROW_LINES |
    88                       wx.TR_COLUMN_LINES |
    88                       wx.TR_COLUMN_LINES |
    89                       wx.TR_HIDE_ROOT |
    89                       wx.TR_HIDE_ROOT |
    90                       wx.TR_FULL_ROW_HIGHLIGHT)
    90                       wx.TR_FULL_ROW_HIGHLIGHT)
    91         self.VariablesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN,
    91         self.VariablesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN,
    92             self.OnVariablesGridLeftClick)
    92             self.OnVariablesGridLeftClick)
    93         self.AddWindow(self.VariablesGrid, flag=wx.GROW)
    93         self.AddWindow(self.VariablesGrid, flag=wx.GROW)
    94         
    94 
    95         self.Filters = []
    95         self.Filters = []
    96         for desc, value in VARIABLES_FILTERS:
    96         for desc, value in VARIABLES_FILTERS:
    97             self.VariablesFilter.Append(desc)
    97             self.VariablesFilter.Append(desc)
    98             self.Filters.append(value)
    98             self.Filters.append(value)
    99         
    99 
   100         self.VariablesFilter.SetSelection(0)
   100         self.VariablesFilter.SetSelection(0)
   101         self.CurrentFilter = self.Filters[0]
   101         self.CurrentFilter = self.Filters[0]
   102         self.VariablesFilterFirstCharacter = True
   102         self.VariablesFilterFirstCharacter = True
   103         
   103 
   104         if position_column:
   104         if position_column:
   105             for colname, colsize, colalign in zip(GetVariablesTableColnames(position_column),
   105             for colname, colsize, colalign in zip(GetVariablesTableColnames(position_column),
   106                                                   [40, 80, 350, 80, 100, 80, 150],
   106                                                   [40, 80, 350, 80, 100, 80, 150],
   107                                                   [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, 
   107                                                   [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT,
   108                                                    wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, 
   108                                                    wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT,
   109                                                    wx.ALIGN_LEFT]):
   109                                                    wx.ALIGN_LEFT]):
   110                 self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
   110                 self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
   111             self.VariablesGrid.SetMainColumn(2)
   111             self.VariablesGrid.SetMainColumn(2)
   112         else:
   112         else:
   113             for colname, colsize, colalign in zip(GetVariablesTableColnames(),
   113             for colname, colsize, colalign in zip(GetVariablesTableColnames(),
   114                                                   [40, 350, 80, 100, 80, 150],
   114                                                   [40, 350, 80, 100, 80, 150],
   115                                                   [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, 
   115                                                   [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT,
   116                                                    wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]):
   116                                                    wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]):
   117                 self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
   117                 self.VariablesGrid.AddColumn(_(colname), colsize, colalign)
   118             self.VariablesGrid.SetMainColumn(1)
   118             self.VariablesGrid.SetMainColumn(1)
   119     
   119 
   120     def RefreshView(self):
   120     def RefreshView(self):
   121         entries = self.Controler.GetSlaveVariables(self.CurrentFilter)
   121         entries = self.Controler.GetSlaveVariables(self.CurrentFilter)
   122         self.RefreshVariablesGrid(entries)
   122         self.RefreshVariablesGrid(entries)
   123     
   123 
   124     def RefreshVariablesGrid(self, entries):
   124     def RefreshVariablesGrid(self, entries):
   125         root = self.VariablesGrid.GetRootItem()
   125         root = self.VariablesGrid.GetRootItem()
   126         if not root.IsOk():
   126         if not root.IsOk():
   127             root = self.VariablesGrid.AddRoot(_("Slave entries"))
   127             root = self.VariablesGrid.AddRoot(_("Slave entries"))
   128         self.GenerateVariablesGridBranch(root, entries, GetVariablesTableColnames(self.PositionColumn))
   128         self.GenerateVariablesGridBranch(root, entries, GetVariablesTableColnames(self.PositionColumn))
   129         self.VariablesGrid.Expand(root)
   129         self.VariablesGrid.Expand(root)
   130         
   130 
   131     def GenerateVariablesGridBranch(self, root, entries, colnames, idx=0):
   131     def GenerateVariablesGridBranch(self, root, entries, colnames, idx=0):
   132         item, root_cookie = self.VariablesGrid.GetFirstChild(root)
   132         item, root_cookie = self.VariablesGrid.GetFirstChild(root)
   133         
   133 
   134         no_more_items = not item.IsOk()
   134         no_more_items = not item.IsOk()
   135         for entry in entries:
   135         for entry in entries:
   136             idx += 1
   136             idx += 1
   137             if no_more_items:
   137             if no_more_items:
   138                 item = self.VariablesGrid.AppendItem(root, "")
   138                 item = self.VariablesGrid.AppendItem(root, "")
   151             self.VariablesGrid.SetItemPyData(item, entry)
   151             self.VariablesGrid.SetItemPyData(item, entry)
   152             idx = self.GenerateVariablesGridBranch(item, entry["children"], colnames, idx)
   152             idx = self.GenerateVariablesGridBranch(item, entry["children"], colnames, idx)
   153             if not no_more_items:
   153             if not no_more_items:
   154                 item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
   154                 item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
   155                 no_more_items = not item.IsOk()
   155                 no_more_items = not item.IsOk()
   156         
   156 
   157         if not no_more_items:
   157         if not no_more_items:
   158             to_delete = []
   158             to_delete = []
   159             while item.IsOk():
   159             while item.IsOk():
   160                 to_delete.append(item)
   160                 to_delete.append(item)
   161                 item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
   161                 item, root_cookie = self.VariablesGrid.GetNextChild(root, root_cookie)
   162             for item in to_delete:
   162             for item in to_delete:
   163                 self.VariablesGrid.Delete(item)
   163                 self.VariablesGrid.Delete(item)
   164         
   164 
   165         return idx
   165         return idx
   166     
   166 
   167     def OnVariablesFilterChanged(self, event):
   167     def OnVariablesFilterChanged(self, event):
   168         filter = self.VariablesFilter.GetSelection()
   168         filter = self.VariablesFilter.GetSelection()
   169         if filter != -1:
   169         if filter != -1:
   170             self.CurrentFilter = self.Filters[filter]
   170             self.CurrentFilter = self.Filters[filter]
   171             self.RefreshView()
   171             self.RefreshView()
   188                     self.VariablesFilter.SetSelection(self.Filters.index(self.CurrentFilter))
   188                     self.VariablesFilter.SetSelection(self.Filters.index(self.CurrentFilter))
   189                 else:
   189                 else:
   190                     self.VariablesFilter.SetValue(VARIABLE_INDEX_FILTER_FORMAT % self.CurrentFilter[0])
   190                     self.VariablesFilter.SetValue(VARIABLE_INDEX_FILTER_FORMAT % self.CurrentFilter[0])
   191         self.VariablesFilterFirstCharacter = True
   191         self.VariablesFilterFirstCharacter = True
   192         event.Skip()
   192         event.Skip()
   193     
   193 
   194     def OnVariablesFilterKeyDown(self, event):
   194     def OnVariablesFilterKeyDown(self, event):
   195         if self.VariablesFilterFirstCharacter:
   195         if self.VariablesFilterFirstCharacter:
   196             keycode = event.GetKeyCode()
   196             keycode = event.GetKeyCode()
   197             if keycode not in [wx.WXK_RETURN, 
   197             if keycode not in [wx.WXK_RETURN,
   198                                wx.WXK_NUMPAD_ENTER]:
   198                                wx.WXK_NUMPAD_ENTER]:
   199                 self.VariablesFilterFirstCharacter = False
   199                 self.VariablesFilterFirstCharacter = False
   200                 if keycode not in NAVIGATION_KEYS:
   200                 if keycode not in NAVIGATION_KEYS:
   201                     self.VariablesFilter.SetValue("")
   201                     self.VariablesFilter.SetValue("")
   202             if keycode not in [wx.WXK_DELETE, 
   202             if keycode not in [wx.WXK_DELETE,
   203                                wx.WXK_NUMPAD_DELETE, 
   203                                wx.WXK_NUMPAD_DELETE,
   204                                wx.WXK_BACK]:
   204                                wx.WXK_BACK]:
   205                 event.Skip()
   205                 event.Skip()
   206         else:
   206         else:
   207             event.Skip()
   207             event.Skip()
   208     
   208 
   209     def OnVariablesGridLeftClick(self, event):
   209     def OnVariablesGridLeftClick(self, event):
   210         item, flags, col = self.VariablesGrid.HitTest(event.GetPosition())
   210         item, flags, col = self.VariablesGrid.HitTest(event.GetPosition())
   211         if item.IsOk():
   211         if item.IsOk():
   212             entry = self.VariablesGrid.GetItemPyData(item)
   212             entry = self.VariablesGrid.GetItemPyData(item)
   213             data_type = entry.get("Type", "")
   213             data_type = entry.get("Type", "")
   214             data_size = self.Controler.GetSizeOfType(data_type)
   214             data_size = self.Controler.GetSizeOfType(data_type)
   215             
   215 
   216             if col == -1 and data_size is not None:
   216             if col == -1 and data_size is not None:
   217                 pdo_mapping = entry.get("PDOMapping", "")
   217                 pdo_mapping = entry.get("PDOMapping", "")
   218                 access = entry.get("Access", "")
   218                 access = entry.get("Access", "")
   219                 entry_index = self.Controler.ExtractHexDecValue(entry.get("Index", "0"))
   219                 entry_index = self.Controler.ExtractHexDecValue(entry.get("Index", "0"))
   220                 entry_subindex = self.Controler.ExtractHexDecValue(entry.get("SubIndex", "0"))
   220                 entry_subindex = self.Controler.ExtractHexDecValue(entry.get("SubIndex", "0"))
   223                     slave_pos = self.Controler.ExtractHexDecValue(entry.get("Position", "0"))
   223                     slave_pos = self.Controler.ExtractHexDecValue(entry.get("Position", "0"))
   224                     location += (slave_pos,)
   224                     location += (slave_pos,)
   225                     node_name = self.Controler.GetSlaveName(slave_pos)
   225                     node_name = self.Controler.GetSlaveName(slave_pos)
   226                 else:
   226                 else:
   227                     node_name = self.Controler.CTNName()
   227                     node_name = self.Controler.CTNName()
   228                 
   228 
   229                 if pdo_mapping != "":
   229                 if pdo_mapping != "":
   230                     var_name = "%s_%4.4x_%2.2x" % (node_name, entry_index, entry_subindex)
   230                     var_name = "%s_%4.4x_%2.2x" % (node_name, entry_index, entry_subindex)
   231                     if pdo_mapping == "T":
   231                     if pdo_mapping == "T":
   232                         dir = "%I"
   232                         dir = "%I"
   233                     else:
   233                     else:
   234                         dir = "%Q"
   234                         dir = "%Q"
   235                     location = "%s%s" % (dir, data_size) + \
   235                     location = "%s%s" % (dir, data_size) + \
   236                                ".".join(map(lambda x:str(x), location + (entry_index, entry_subindex)))
   236                                ".".join(map(lambda x:str(x), location + (entry_index, entry_subindex)))
   237                     
   237 
   238                     data = wx.TextDataObject(str((location, "location", data_type, var_name, "", access)))
   238                     data = wx.TextDataObject(str((location, "location", data_type, var_name, "", access)))
   239                     dragSource = wx.DropSource(self.VariablesGrid)
   239                     dragSource = wx.DropSource(self.VariablesGrid)
   240                     dragSource.SetData(data)
   240                     dragSource.SetData(data)
   241                     dragSource.DoDragDrop()
   241                     dragSource.DoDragDrop()
   242                     return
   242                     return
   243                 
   243 
   244                 elif self.PositionColumn:
   244                 elif self.PositionColumn:
   245                     location = self.Controler.GetCurrentLocation() +\
   245                     location = self.Controler.GetCurrentLocation() +\
   246                                (slave_pos, entry_index, entry_subindex)
   246                                (slave_pos, entry_index, entry_subindex)
   247                     data = wx.TextDataObject(str((location, "variable", access)))
   247                     data = wx.TextDataObject(str((location, "variable", access)))
   248                     dragSource = wx.DropSource(self.VariablesGrid)
   248                     dragSource = wx.DropSource(self.VariablesGrid)
   249                     dragSource.SetData(data)
   249                     dragSource.SetData(data)
   250                     dragSource.DoDragDrop()
   250                     dragSource.DoDragDrop()
   251                     return
   251                     return
   252         
   252 
   253         event.Skip()
   253         event.Skip()
   254 
   254 
   255 class NodeEditor(ConfTreeNodeEditor):
   255 class NodeEditor(ConfTreeNodeEditor):
   256     
   256 
   257     CONFNODEEDITOR_TABS = [
   257     CONFNODEEDITOR_TABS = [
   258         (_("Ethercat node"), "_create_EthercatNodeEditor"),
   258         (_("Ethercat node"), "_create_EthercatNodeEditor"),
   259         # Add Notebook Tab for EtherCAT Management Treebook
   259         # Add Notebook Tab for EtherCAT Management Treebook
   260         (_("EtherCAT Management"), "_create_EtherCATManagementEditor")
   260         (_("EtherCAT Management"), "_create_EtherCATManagementEditor")
   261         ]
   261         ]
   262     
   262 
   263     def _create_EthercatNodeEditor(self, prnt):
   263     def _create_EthercatNodeEditor(self, prnt):
   264         self.EthercatNodeEditor = wx.Panel(prnt, style=wx.TAB_TRAVERSAL)
   264         self.EthercatNodeEditor = wx.Panel(prnt, style=wx.TAB_TRAVERSAL)
   265         
   265 
   266         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
   266         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
   267         main_sizer.AddGrowableCol(0)
   267         main_sizer.AddGrowableCol(0)
   268         main_sizer.AddGrowableRow(1)
   268         main_sizer.AddGrowableRow(1)
   269         
   269 
   270         variables_label = wx.StaticText(self.EthercatNodeEditor,
   270         variables_label = wx.StaticText(self.EthercatNodeEditor,
   271               label=_('Variable entries:'))
   271               label=_('Variable entries:'))
   272         main_sizer.AddWindow(variables_label, border=10, flag=wx.TOP|wx.LEFT|wx.RIGHT)
   272         main_sizer.AddWindow(variables_label, border=10, flag=wx.TOP|wx.LEFT|wx.RIGHT)
   273         
   273 
   274         self.NodeVariables = NodeVariablesSizer(self.EthercatNodeEditor, self.Controler)
   274         self.NodeVariables = NodeVariablesSizer(self.EthercatNodeEditor, self.Controler)
   275         main_sizer.AddSizer(self.NodeVariables, border=10, 
   275         main_sizer.AddSizer(self.NodeVariables, border=10,
   276             flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
   276             flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
   277                 
   277 
   278         self.EthercatNodeEditor.SetSizer(main_sizer)
   278         self.EthercatNodeEditor.SetSizer(main_sizer)
   279 
   279 
   280         return self.EthercatNodeEditor
   280         return self.EthercatNodeEditor
   281     
   281 
   282     def __init__(self, parent, controler, window):
   282     def __init__(self, parent, controler, window):
   283         ConfTreeNodeEditor.__init__(self, parent, controler, window)
   283         ConfTreeNodeEditor.__init__(self, parent, controler, window)
   284         
   284 
   285         # add Contoler for use EthercatSlave.py Method
   285         # add Contoler for use EthercatSlave.py Method
   286         self.Controler = controler
   286         self.Controler = controler
   287         
   287 
   288     def GetBufferState(self):
   288     def GetBufferState(self):
   289         return False, False
   289         return False, False
   290         
   290 
   291     def RefreshView(self):
   291     def RefreshView(self):
   292         ConfTreeNodeEditor.RefreshView(self)
   292         ConfTreeNodeEditor.RefreshView(self)
   293     
   293 
   294         self.NodeVariables.RefreshView()
   294         self.NodeVariables.RefreshView()
   295 
   295 
   296     # -------------------For EtherCAT Management ----------------------------------------------    
   296     # -------------------For EtherCAT Management ----------------------------------------------
   297     def _create_EtherCATManagementEditor(self, prnt):
   297     def _create_EtherCATManagementEditor(self, prnt):
   298         self.EtherCATManagementEditor = wx.ScrolledWindow(prnt,
   298         self.EtherCATManagementEditor = wx.ScrolledWindow(prnt,
   299             style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
   299             style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
   300         self.EtherCATManagementEditor.Bind(wx.EVT_SIZE, self.OnResize)
   300         self.EtherCATManagementEditor.Bind(wx.EVT_SIZE, self.OnResize)
   301 
   301 
   302         self.EtherCATManagermentEditor_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
   302         self.EtherCATManagermentEditor_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
   303         self.EtherCATManagermentEditor_Main_Sizer.AddGrowableCol(0)
   303         self.EtherCATManagermentEditor_Main_Sizer.AddGrowableCol(0)
   304         self.EtherCATManagermentEditor_Main_Sizer.AddGrowableRow(0)
   304         self.EtherCATManagermentEditor_Main_Sizer.AddGrowableRow(0)
   305         
   305 
   306         self.EtherCATManagementTreebook = EtherCATManagementTreebook(self.EtherCATManagementEditor, self.Controler, self)
   306         self.EtherCATManagementTreebook = EtherCATManagementTreebook(self.EtherCATManagementEditor, self.Controler, self)
   307           
   307 
   308         self.EtherCATManagermentEditor_Main_Sizer.AddSizer(self.EtherCATManagementTreebook, border=10, flag=wx.GROW)
   308         self.EtherCATManagermentEditor_Main_Sizer.AddSizer(self.EtherCATManagementTreebook, border=10, flag=wx.GROW)
   309 
   309 
   310         self.EtherCATManagementEditor.SetSizer(self.EtherCATManagermentEditor_Main_Sizer)
   310         self.EtherCATManagementEditor.SetSizer(self.EtherCATManagermentEditor_Main_Sizer)
   311         return self.EtherCATManagementEditor
   311         return self.EtherCATManagementEditor
   312     
   312 
   313     def OnResize(self, event):
   313     def OnResize(self, event):
   314         self.EtherCATManagementEditor.GetBestSize()
   314         self.EtherCATManagementEditor.GetBestSize()
   315         xstart, ystart = self.EtherCATManagementEditor.GetViewStart()
   315         xstart, ystart = self.EtherCATManagementEditor.GetViewStart()
   316         window_size = self.EtherCATManagementEditor.GetClientSize()
   316         window_size = self.EtherCATManagementEditor.GetClientSize()
   317         maxx, maxy = self.EtherCATManagementEditor.GetMinSize()
   317         maxx, maxy = self.EtherCATManagementEditor.GetMinSize()
   318         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
   318         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
   319         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
   319         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
   320         self.EtherCATManagementEditor.Scroll(posx, posy)
   320         self.EtherCATManagementEditor.Scroll(posx, posy)
   321         self.EtherCATManagementEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
   321         self.EtherCATManagementEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
   322                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
   322                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
   323         event.Skip()
   323         event.Skip()
   324     # -------------------------------------------------------------------------------------------------------
   324     # -------------------------------------------------------------------------------------------------------
   325 
   325 
   326 CIA402NodeEditor = NodeEditor
   326 CIA402NodeEditor = NodeEditor
   327 
   327 
   328 
   328 
   329 def GetProcessVariablesTableColnames():
   329 def GetProcessVariablesTableColnames():
   330     _ = lambda x : x
   330     _ = lambda x : x
   331     return ["#", _("Name"), 
   331     return ["#", _("Name"),
   332             _("Read from (nodeid, index, subindex)"), 
   332             _("Read from (nodeid, index, subindex)"),
   333             _("Write to (nodeid, index, subindex)"),
   333             _("Write to (nodeid, index, subindex)"),
   334             _("Description")]
   334             _("Description")]
   335 
   335 
   336 class ProcessVariablesTable(CustomTable):
   336 class ProcessVariablesTable(CustomTable):
   337     
   337 
   338     def GetValue(self, row, col):
   338     def GetValue(self, row, col):
   339         if row < self.GetNumberRows():
   339         if row < self.GetNumberRows():
   340             if col == 0:
   340             if col == 0:
   341                 return row + 1
   341                 return row + 1
   342             colname = self.GetColLabelValue(col, False)
   342             colname = self.GetColLabelValue(col, False)
   349                 value = self.data[row].get("WriteTo", "")
   349                 value = self.data[row].get("WriteTo", "")
   350                 if value == "":
   350                 if value == "":
   351                     return value
   351                     return value
   352                 return "%d, #x%0.4X, #x%0.2X" % value
   352                 return "%d, #x%0.4X, #x%0.2X" % value
   353             return self.data[row].get(colname, "")
   353             return self.data[row].get(colname, "")
   354     
   354 
   355     def SetValue(self, row, col, value):
   355     def SetValue(self, row, col, value):
   356         if col < len(self.colnames):
   356         if col < len(self.colnames):
   357             colname = self.GetColLabelValue(col, False)
   357             colname = self.GetColLabelValue(col, False)
   358             if colname.startswith("Read from"):
   358             if colname.startswith("Read from"):
   359                 self.data[row]["ReadFrom"] = value
   359                 self.data[row]["ReadFrom"] = value
   360             elif colname.startswith("Write to"):
   360             elif colname.startswith("Write to"):
   361                 self.data[row]["WriteTo"] = value
   361                 self.data[row]["WriteTo"] = value
   362             else:
   362             else:
   363                 self.data[row][colname] = value
   363                 self.data[row][colname] = value
   364     
   364 
   365     def _updateColAttrs(self, grid):
   365     def _updateColAttrs(self, grid):
   366         """
   366         """
   367         wx.grid.Grid -> update the column attributes to add the
   367         wx.grid.Grid -> update the column attributes to add the
   368         appropriate renderer given the column name.
   368         appropriate renderer given the column name.
   369 
   369 
   378                     editor = wx.grid.GridCellTextEditor()
   378                     editor = wx.grid.GridCellTextEditor()
   379                     renderer = wx.grid.GridCellStringRenderer()
   379                     renderer = wx.grid.GridCellStringRenderer()
   380                     grid.SetReadOnly(row, col, False)
   380                     grid.SetReadOnly(row, col, False)
   381                 else:
   381                 else:
   382                     grid.SetReadOnly(row, col, True)
   382                     grid.SetReadOnly(row, col, True)
   383                 
   383 
   384                 grid.SetCellEditor(row, col, editor)
   384                 grid.SetCellEditor(row, col, editor)
   385                 grid.SetCellRenderer(row, col, renderer)
   385                 grid.SetCellRenderer(row, col, renderer)
   386                 
   386 
   387             self.ResizeRow(grid, row)
   387             self.ResizeRow(grid, row)
   388 
   388 
   389 class ProcessVariableDropTarget(wx.TextDropTarget):
   389 class ProcessVariableDropTarget(wx.TextDropTarget):
   390     
   390 
   391     def __init__(self, parent):
   391     def __init__(self, parent):
   392         wx.TextDropTarget.__init__(self)
   392         wx.TextDropTarget.__init__(self)
   393         self.ParentWindow = parent
   393         self.ParentWindow = parent
   394     
   394 
   395     def OnDropText(self, x, y, data):
   395     def OnDropText(self, x, y, data):
   396         self.ParentWindow.Select()
   396         self.ParentWindow.Select()
   397         x, y = self.ParentWindow.ProcessVariablesGrid.CalcUnscrolledPosition(x, y)
   397         x, y = self.ParentWindow.ProcessVariablesGrid.CalcUnscrolledPosition(x, y)
   398         col = self.ParentWindow.ProcessVariablesGrid.XToCol(x)
   398         col = self.ParentWindow.ProcessVariablesGrid.XToCol(x)
   399         row = self.ParentWindow.ProcessVariablesGrid.YToRow(y - self.ParentWindow.ProcessVariablesGrid.GetColLabelSize())
   399         row = self.ParentWindow.ProcessVariablesGrid.YToRow(y - self.ParentWindow.ProcessVariablesGrid.GetColLabelSize())
   411             if values[1] == "location":
   411             if values[1] == "location":
   412                 result = LOCATION_MODEL.match(values[0])
   412                 result = LOCATION_MODEL.match(values[0])
   413                 if result is not None:
   413                 if result is not None:
   414                     location = map(int, result.group(1).split('.'))
   414                     location = map(int, result.group(1).split('.'))
   415                 master_location = self.ParentWindow.GetMasterLocation()
   415                 master_location = self.ParentWindow.GetMasterLocation()
   416                 if (master_location == tuple(location[:len(master_location)]) and 
   416                 if (master_location == tuple(location[:len(master_location)]) and
   417                     len(location) - len(master_location) == 3):
   417                     len(location) - len(master_location) == 3):
   418                     values = tuple(location[len(master_location):])
   418                     values = tuple(location[len(master_location):])
   419                     var_type = self.ParentWindow.Controler.GetSlaveVariableDataType(*values)
   419                     var_type = self.ParentWindow.Controler.GetSlaveVariableDataType(*values)
   420                     if col == 2:
   420                     if col == 2:
   421                         other_values = self.ParentWindow.ProcessVariablesTable.GetValueByName(row, "WriteTo")
   421                         other_values = self.ParentWindow.ProcessVariablesTable.GetValueByName(row, "WriteTo")
   434                         self.ParentWindow.RefreshProcessVariables()
   434                         self.ParentWindow.RefreshProcessVariables()
   435                     else:
   435                     else:
   436                         message = _("'Read from' and 'Write to' variables types are not compatible")
   436                         message = _("'Read from' and 'Write to' variables types are not compatible")
   437                 else:
   437                 else:
   438                     message = _("Invalid value \"%s\" for process variable")%data
   438                     message = _("Invalid value \"%s\" for process variable")%data
   439                     
   439 
   440         if message is not None:
   440         if message is not None:
   441             wx.CallAfter(self.ShowMessage, message)
   441             wx.CallAfter(self.ShowMessage, message)
   442     
   442 
   443     def ShowMessage(self, message):
   443     def ShowMessage(self, message):
   444         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   444         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   445         message.ShowModal()
   445         message.ShowModal()
   446         message.Destroy()
   446         message.Destroy()
   447 
   447 
   448 def GetStartupCommandsTableColnames():
   448 def GetStartupCommandsTableColnames():
   449     _ = lambda x : x
   449     _ = lambda x : x
   450     return [_("Position"), _("Index"), _("Subindex"), _("Value"), _("Description")]
   450     return [_("Position"), _("Index"), _("Subindex"), _("Value"), _("Description")]
   451 
   451 
   452 class StartupCommandDropTarget(wx.TextDropTarget):
   452 class StartupCommandDropTarget(wx.TextDropTarget):
   453     
   453 
   454     def __init__(self, parent):
   454     def __init__(self, parent):
   455         wx.TextDropTarget.__init__(self)
   455         wx.TextDropTarget.__init__(self)
   456         self.ParentWindow = parent
   456         self.ParentWindow = parent
   457     
   457 
   458     def OnDropText(self, x, y, data):
   458     def OnDropText(self, x, y, data):
   459         self.ParentWindow.Select()
   459         self.ParentWindow.Select()
   460         message = None
   460         message = None
   461         try:
   461         try:
   462             values = eval(data)
   462             values = eval(data)
   476             elif values[1] == "variable":
   476             elif values[1] == "variable":
   477                 location = values[0]
   477                 location = values[0]
   478                 access = values[2]
   478                 access = values[2]
   479             if location is not None:
   479             if location is not None:
   480                 master_location = self.ParentWindow.GetMasterLocation()
   480                 master_location = self.ParentWindow.GetMasterLocation()
   481                 if (master_location == tuple(location[:len(master_location)]) and 
   481                 if (master_location == tuple(location[:len(master_location)]) and
   482                     len(location) - len(master_location) == 3):
   482                     len(location) - len(master_location) == 3):
   483                     if access in ["wo", "rw"]:
   483                     if access in ["wo", "rw"]:
   484                         self.ParentWindow.AddStartupCommand(*location[len(master_location):])
   484                         self.ParentWindow.AddStartupCommand(*location[len(master_location):])
   485                     else:
   485                     else:
   486                         message = _("Entry can't be write through SDO")
   486                         message = _("Entry can't be write through SDO")
   487                 else:
   487                 else:
   488                     message = _("Invalid value \"%s\" for startup command")%data
   488                     message = _("Invalid value \"%s\" for startup command")%data
   489                     
   489 
   490         if message is not None:
   490         if message is not None:
   491             wx.CallAfter(self.ShowMessage, message)
   491             wx.CallAfter(self.ShowMessage, message)
   492     
   492 
   493     def ShowMessage(self, message):
   493     def ShowMessage(self, message):
   494         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   494         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
   495         message.ShowModal()
   495         message.ShowModal()
   496         message.Destroy()
   496         message.Destroy()
   497 
   497 
   512             if colname == "Index":
   512             if colname == "Index":
   513                 return "#x%0.4X" % value
   513                 return "#x%0.4X" % value
   514             elif colname == "Subindex":
   514             elif colname == "Subindex":
   515                 return "#x%0.2X" % value
   515                 return "#x%0.2X" % value
   516             return value
   516             return value
   517     
   517 
   518     def SetValue(self, row, col, value):
   518     def SetValue(self, row, col, value):
   519         if col < len(self.colnames):
   519         if col < len(self.colnames):
   520             colname = self.GetColLabelValue(col, False)
   520             colname = self.GetColLabelValue(col, False)
   521             if colname in ["Index", "Subindex"]:
   521             if colname in ["Index", "Subindex"]:
   522                 if colname == "Index":
   522                 if colname == "Index":
   530                 value = int(value)
   530                 value = int(value)
   531             elif colname == "Position":
   531             elif colname == "Position":
   532                 self.old_value = self.data[row][colname]
   532                 self.old_value = self.data[row][colname]
   533                 value = int(value)
   533                 value = int(value)
   534             self.data[row][colname] = value
   534             self.data[row][colname] = value
   535     
   535 
   536     def GetOldValue(self):
   536     def GetOldValue(self):
   537         return self.old_value
   537         return self.old_value
   538     
   538 
   539     def _updateColAttrs(self, grid):
   539     def _updateColAttrs(self, grid):
   540         """
   540         """
   541         wx.grid.Grid -> update the column attributes to add the
   541         wx.grid.Grid -> update the column attributes to add the
   542         appropriate renderer given the column name.
   542         appropriate renderer given the column name.
   543 
   543 
   552                     editor = wx.grid.GridCellNumberEditor()
   552                     editor = wx.grid.GridCellNumberEditor()
   553                     renderer = wx.grid.GridCellNumberRenderer()
   553                     renderer = wx.grid.GridCellNumberRenderer()
   554                 else:
   554                 else:
   555                     editor = wx.grid.GridCellTextEditor()
   555                     editor = wx.grid.GridCellTextEditor()
   556                     renderer = wx.grid.GridCellStringRenderer()
   556                     renderer = wx.grid.GridCellStringRenderer()
   557                 
   557 
   558                 grid.SetCellEditor(row, col, editor)
   558                 grid.SetCellEditor(row, col, editor)
   559                 grid.SetCellRenderer(row, col, renderer)
   559                 grid.SetCellRenderer(row, col, renderer)
   560                 grid.SetReadOnly(row, col, False)
   560                 grid.SetReadOnly(row, col, False)
   561                 
   561 
   562             self.ResizeRow(grid, row)
   562             self.ResizeRow(grid, row)
   563     
   563 
   564     def GetCommandIndex(self, position, command_idx):
   564     def GetCommandIndex(self, position, command_idx):
   565         for row, command in enumerate(self.data):
   565         for row, command in enumerate(self.data):
   566             if command["Position"] == position and command["command_idx"] == command_idx:
   566             if command["Position"] == position and command["command_idx"] == command_idx:
   567                 return row
   567                 return row
   568         return None
   568         return None
   569 
   569 
   570 class MasterNodesVariablesSizer(NodeVariablesSizer):
   570 class MasterNodesVariablesSizer(NodeVariablesSizer):
   571     
   571 
   572     def __init__(self, parent, controler):
   572     def __init__(self, parent, controler):
   573         NodeVariablesSizer.__init__(self, parent, controler, True)
   573         NodeVariablesSizer.__init__(self, parent, controler, True)
   574         
   574 
   575         self.CurrentNodesFilter = {}
   575         self.CurrentNodesFilter = {}
   576     
   576 
   577     def SetCurrentNodesFilter(self, nodes_filter):
   577     def SetCurrentNodesFilter(self, nodes_filter):
   578         self.CurrentNodesFilter = nodes_filter
   578         self.CurrentNodesFilter = nodes_filter
   579         
   579 
   580     def RefreshView(self):
   580     def RefreshView(self):
   581         if self.CurrentNodesFilter is not None:
   581         if self.CurrentNodesFilter is not None:
   582             args = self.CurrentNodesFilter.copy()
   582             args = self.CurrentNodesFilter.copy()
   583             args["limits"] = self.CurrentFilter
   583             args["limits"] = self.CurrentFilter
   584             entries = self.Controler.GetNodesVariables(**args)
   584             entries = self.Controler.GetNodesVariables(**args)
   585             self.RefreshVariablesGrid(entries)
   585             self.RefreshVariablesGrid(entries)
   586 
   586 
   587 NODE_POSITION_FILTER_FORMAT = _("Node Position: %d")
   587 NODE_POSITION_FILTER_FORMAT = _("Node Position: %d")
   588 
   588 
   589 class MasterEditor(ConfTreeNodeEditor):
   589 class MasterEditor(ConfTreeNodeEditor):
   590     
   590 
   591     CONFNODEEDITOR_TABS = [
   591     CONFNODEEDITOR_TABS = [
   592         (_("Network"), "_create_EthercatMasterEditor"),
   592         (_("Network"), "_create_EthercatMasterEditor"),
   593         (_("Master State"), "_create_MasterStateEditor")
   593         (_("Master State"), "_create_MasterStateEditor")
   594         ]
   594         ]
   595     
   595 
   596     def _create_MasterStateEditor(self, prnt):
   596     def _create_MasterStateEditor(self, prnt):
   597         self.MasterStateEditor = wx.ScrolledWindow(prnt, style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
   597         self.MasterStateEditor = wx.ScrolledWindow(prnt, style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
   598         self.MasterStateEditor.Bind(wx.EVT_SIZE, self.OnResize)
   598         self.MasterStateEditor.Bind(wx.EVT_SIZE, self.OnResize)
   599         
   599 
   600         self.MasterStateEditor_Panel_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
   600         self.MasterStateEditor_Panel_Main_Sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
   601         self.MasterStateEditor_Panel_Main_Sizer.AddGrowableCol(0)
   601         self.MasterStateEditor_Panel_Main_Sizer.AddGrowableCol(0)
   602         self.MasterStateEditor_Panel_Main_Sizer.AddGrowableRow(0)
   602         self.MasterStateEditor_Panel_Main_Sizer.AddGrowableRow(0)
   603         
   603 
   604         self.MasterStateEditor_Panel = MasterStatePanelClass(self.MasterStateEditor, self.Controler)
   604         self.MasterStateEditor_Panel = MasterStatePanelClass(self.MasterStateEditor, self.Controler)
   605         
   605 
   606         self.MasterStateEditor_Panel_Main_Sizer.AddSizer(self.MasterStateEditor_Panel, border=10, flag=wx.GROW)
   606         self.MasterStateEditor_Panel_Main_Sizer.AddSizer(self.MasterStateEditor_Panel, border=10, flag=wx.GROW)
   607          
   607 
   608         self.MasterStateEditor.SetSizer(self.MasterStateEditor_Panel_Main_Sizer)
   608         self.MasterStateEditor.SetSizer(self.MasterStateEditor_Panel_Main_Sizer)
   609         return self.MasterStateEditor
   609         return self.MasterStateEditor
   610     
   610 
   611     def OnResize(self, event):
   611     def OnResize(self, event):
   612         self.MasterStateEditor.GetBestSize()
   612         self.MasterStateEditor.GetBestSize()
   613         xstart, ystart = self.MasterStateEditor.GetViewStart()
   613         xstart, ystart = self.MasterStateEditor.GetViewStart()
   614         window_size = self.MasterStateEditor.GetClientSize()
   614         window_size = self.MasterStateEditor.GetClientSize()
   615         maxx, maxy = self.MasterStateEditor.GetMinSize()
   615         maxx, maxy = self.MasterStateEditor.GetMinSize()
   616         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
   616         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
   617         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
   617         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
   618         self.MasterStateEditor.Scroll(posx, posy)
   618         self.MasterStateEditor.Scroll(posx, posy)
   619         self.MasterStateEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
   619         self.MasterStateEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
   620                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
   620                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
   621         event.Skip()
   621         event.Skip()
   622     
   622 
   623     def _create_EthercatMasterEditor(self, prnt):
   623     def _create_EthercatMasterEditor(self, prnt):
   624         self.EthercatMasterEditor = wx.ScrolledWindow(prnt, 
   624         self.EthercatMasterEditor = wx.ScrolledWindow(prnt,
   625             style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
   625             style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
   626         self.EthercatMasterEditor.Bind(wx.EVT_SIZE, self.OnResize)
   626         self.EthercatMasterEditor.Bind(wx.EVT_SIZE, self.OnResize)
   627         
   627 
   628         self.EthercatMasterEditorSizer = wx.BoxSizer(wx.VERTICAL)
   628         self.EthercatMasterEditorSizer = wx.BoxSizer(wx.VERTICAL)
   629         
   629 
   630         self.NodesFilter = wx.ComboBox(self.EthercatMasterEditor,
   630         self.NodesFilter = wx.ComboBox(self.EthercatMasterEditor,
   631             style=wx.TE_PROCESS_ENTER)
   631             style=wx.TE_PROCESS_ENTER)
   632         self.Bind(wx.EVT_COMBOBOX, self.OnNodesFilterChanged, self.NodesFilter)
   632         self.Bind(wx.EVT_COMBOBOX, self.OnNodesFilterChanged, self.NodesFilter)
   633         self.Bind(wx.EVT_TEXT_ENTER, self.OnNodesFilterChanged, self.NodesFilter)
   633         self.Bind(wx.EVT_TEXT_ENTER, self.OnNodesFilterChanged, self.NodesFilter)
   634         self.NodesFilter.Bind(wx.EVT_CHAR, self.OnNodesFilterKeyDown)
   634         self.NodesFilter.Bind(wx.EVT_CHAR, self.OnNodesFilterKeyDown)
   635         
   635 
   636         process_variables_header = wx.BoxSizer(wx.HORIZONTAL)
   636         process_variables_header = wx.BoxSizer(wx.HORIZONTAL)
   637         
   637 
   638         process_variables_label = wx.StaticText(self.EthercatMasterEditor,
   638         process_variables_label = wx.StaticText(self.EthercatMasterEditor,
   639               label=_("Process variables mapped between nodes:"))
   639               label=_("Process variables mapped between nodes:"))
   640         process_variables_header.AddWindow(process_variables_label, 1,
   640         process_variables_header.AddWindow(process_variables_label, 1,
   641               flag=wx.ALIGN_CENTER_VERTICAL)
   641               flag=wx.ALIGN_CENTER_VERTICAL)
   642         
   642 
   643         for name, bitmap, help in [
   643         for name, bitmap, help in [
   644                 ("AddVariableButton", "add_element", _("Add process variable")),
   644                 ("AddVariableButton", "add_element", _("Add process variable")),
   645                 ("DeleteVariableButton", "remove_element", _("Remove process variable")),
   645                 ("DeleteVariableButton", "remove_element", _("Remove process variable")),
   646                 ("UpVariableButton", "up", _("Move process variable up")),
   646                 ("UpVariableButton", "up", _("Move process variable up")),
   647                 ("DownVariableButton", "down", _("Move process variable down"))]:
   647                 ("DownVariableButton", "down", _("Move process variable down"))]:
   648             button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), 
   648             button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap),
   649                   size=wx.Size(28, 28), style=wx.NO_BORDER)
   649                   size=wx.Size(28, 28), style=wx.NO_BORDER)
   650             button.SetToolTipString(help)
   650             button.SetToolTipString(help)
   651             setattr(self, name, button)
   651             setattr(self, name, button)
   652             process_variables_header.AddWindow(button, border=5, flag=wx.LEFT)
   652             process_variables_header.AddWindow(button, border=5, flag=wx.LEFT)
   653         
   653 
   654         self.ProcessVariablesGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
   654         self.ProcessVariablesGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
   655         self.ProcessVariablesGrid.SetMinSize(wx.Size(0, 150))
   655         self.ProcessVariablesGrid.SetMinSize(wx.Size(0, 150))
   656         self.ProcessVariablesGrid.SetDropTarget(ProcessVariableDropTarget(self))
   656         self.ProcessVariablesGrid.SetDropTarget(ProcessVariableDropTarget(self))
   657         self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, 
   657         self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
   658               self.OnProcessVariablesGridCellChange)
   658               self.OnProcessVariablesGridCellChange)
   659         self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, 
   659         self.ProcessVariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK,
   660               self.OnProcessVariablesGridCellLeftClick)
   660               self.OnProcessVariablesGridCellLeftClick)
   661         self.ProcessVariablesGrid.Bind(wx.EVT_KEY_DOWN, self.OnProcessVariablesGridKeyDown)
   661         self.ProcessVariablesGrid.Bind(wx.EVT_KEY_DOWN, self.OnProcessVariablesGridKeyDown)
   662         
   662 
   663         startup_commands_header = wx.BoxSizer(wx.HORIZONTAL)
   663         startup_commands_header = wx.BoxSizer(wx.HORIZONTAL)
   664         
   664 
   665         startup_commands_label = wx.StaticText(self.EthercatMasterEditor,
   665         startup_commands_label = wx.StaticText(self.EthercatMasterEditor,
   666               label=_("Startup service variables assignments:"))
   666               label=_("Startup service variables assignments:"))
   667         startup_commands_header.AddWindow(startup_commands_label, 1,
   667         startup_commands_header.AddWindow(startup_commands_label, 1,
   668               flag=wx.ALIGN_CENTER_VERTICAL)
   668               flag=wx.ALIGN_CENTER_VERTICAL)
   669         
   669 
   670         for name, bitmap, help in [
   670         for name, bitmap, help in [
   671                 ("AddCommandButton", "add_element", _("Add startup service variable")),
   671                 ("AddCommandButton", "add_element", _("Add startup service variable")),
   672                 ("DeleteCommandButton", "remove_element", _("Remove startup service variable"))]:
   672                 ("DeleteCommandButton", "remove_element", _("Remove startup service variable"))]:
   673             button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap), 
   673             button = wx.lib.buttons.GenBitmapButton(self.EthercatMasterEditor, bitmap=GetBitmap(bitmap),
   674                   size=wx.Size(28, 28), style=wx.NO_BORDER)
   674                   size=wx.Size(28, 28), style=wx.NO_BORDER)
   675             button.SetToolTipString(help)
   675             button.SetToolTipString(help)
   676             setattr(self, name, button)
   676             setattr(self, name, button)
   677             startup_commands_header.AddWindow(button, border=5, flag=wx.LEFT)
   677             startup_commands_header.AddWindow(button, border=5, flag=wx.LEFT)
   678         
   678 
   679         self.StartupCommandsGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
   679         self.StartupCommandsGrid = CustomGrid(self.EthercatMasterEditor, style=wx.VSCROLL)
   680         self.StartupCommandsGrid.SetDropTarget(StartupCommandDropTarget(self))
   680         self.StartupCommandsGrid.SetDropTarget(StartupCommandDropTarget(self))
   681         self.StartupCommandsGrid.SetMinSize(wx.Size(0, 150))
   681         self.StartupCommandsGrid.SetMinSize(wx.Size(0, 150))
   682         self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, 
   682         self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
   683               self.OnStartupCommandsGridCellChange)
   683               self.OnStartupCommandsGridCellChange)
   684         self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, 
   684         self.StartupCommandsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN,
   685               self.OnStartupCommandsGridEditorShow)
   685               self.OnStartupCommandsGridEditorShow)
   686         
   686 
   687         self.NodesVariables = MasterNodesVariablesSizer(self.EthercatMasterEditor, self.Controler)
   687         self.NodesVariables = MasterNodesVariablesSizer(self.EthercatMasterEditor, self.Controler)
   688         
   688 
   689         main_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Node filter:"))
   689         main_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Node filter:"))
   690         staticbox_sizer = wx.StaticBoxSizer(main_staticbox, wx.VERTICAL)
   690         staticbox_sizer = wx.StaticBoxSizer(main_staticbox, wx.VERTICAL)
   691         self.EthercatMasterEditorSizer.AddSizer(staticbox_sizer, 0, border=10, flag=wx.GROW|wx.ALL)
   691         self.EthercatMasterEditorSizer.AddSizer(staticbox_sizer, 0, border=10, flag=wx.GROW|wx.ALL)
   692         
   692 
   693         main_staticbox_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=6, vgap=0)
   693         main_staticbox_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=6, vgap=0)
   694         main_staticbox_sizer.AddGrowableCol(0)
   694         main_staticbox_sizer.AddGrowableCol(0)
   695         main_staticbox_sizer.AddGrowableRow(2)
   695         main_staticbox_sizer.AddGrowableRow(2)
   696         main_staticbox_sizer.AddGrowableRow(4)
   696         main_staticbox_sizer.AddGrowableRow(4)
   697         main_staticbox_sizer.AddGrowableRow(5)
   697         main_staticbox_sizer.AddGrowableRow(5)
   698         staticbox_sizer.AddSizer(main_staticbox_sizer, 1, flag=wx.GROW)
   698         staticbox_sizer.AddSizer(main_staticbox_sizer, 1, flag=wx.GROW)
   699         main_staticbox_sizer.AddWindow(self.NodesFilter, border=5, flag=wx.GROW|wx.ALL)
   699         main_staticbox_sizer.AddWindow(self.NodesFilter, border=5, flag=wx.GROW|wx.ALL)
   700         main_staticbox_sizer.AddSizer(process_variables_header, border=5, 
   700         main_staticbox_sizer.AddSizer(process_variables_header, border=5,
   701               flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   701               flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   702         main_staticbox_sizer.AddWindow(self.ProcessVariablesGrid, 1, 
   702         main_staticbox_sizer.AddWindow(self.ProcessVariablesGrid, 1,
   703               border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   703               border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   704         main_staticbox_sizer.AddSizer(startup_commands_header, 
   704         main_staticbox_sizer.AddSizer(startup_commands_header,
   705               border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   705               border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   706         main_staticbox_sizer.AddWindow(self.StartupCommandsGrid, 1, 
   706         main_staticbox_sizer.AddWindow(self.StartupCommandsGrid, 1,
   707               border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   707               border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   708         
   708 
   709         second_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Nodes variables filter:"))
   709         second_staticbox = wx.StaticBox(self.EthercatMasterEditor, label=_("Nodes variables filter:"))
   710         second_staticbox_sizer = wx.StaticBoxSizer(second_staticbox, wx.VERTICAL)
   710         second_staticbox_sizer = wx.StaticBoxSizer(second_staticbox, wx.VERTICAL)
   711         second_staticbox_sizer.AddSizer(self.NodesVariables, 1, border=5, flag=wx.GROW|wx.ALL)
   711         second_staticbox_sizer.AddSizer(self.NodesVariables, 1, border=5, flag=wx.GROW|wx.ALL)
   712         
   712 
   713         main_staticbox_sizer.AddSizer(second_staticbox_sizer, 1, 
   713         main_staticbox_sizer.AddSizer(second_staticbox_sizer, 1,
   714             border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   714             border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
   715         
   715 
   716         self.EthercatMasterEditor.SetSizer(self.EthercatMasterEditorSizer)
   716         self.EthercatMasterEditor.SetSizer(self.EthercatMasterEditorSizer)
   717         
   717 
   718         return self.EthercatMasterEditor
   718         return self.EthercatMasterEditor
   719 
   719 
   720     def __init__(self, parent, controler, window):
   720     def __init__(self, parent, controler, window):
   721         ConfTreeNodeEditor.__init__(self, parent, controler, window)
   721         ConfTreeNodeEditor.__init__(self, parent, controler, window)
   722         
   722 
   723         # ------------------------------------------------------------------
   723         # ------------------------------------------------------------------
   724         self.Controler = controler
   724         self.Controler = controler
   725         # ------------------------------------------------------------------
   725         # ------------------------------------------------------------------
   726         
   726 
   727         self.ProcessVariables = []
   727         self.ProcessVariables = []
   728         self.CellShown = None
   728         self.CellShown = None
   729         self.NodesFilterFirstCharacter = True
   729         self.NodesFilterFirstCharacter = True
   730         
   730 
   731         self.ProcessVariablesDefaultValue = {"Name": "", "ReadFrom": "", "WriteTo": "", "Description": ""}
   731         self.ProcessVariablesDefaultValue = {"Name": "", "ReadFrom": "", "WriteTo": "", "Description": ""}
   732         self.ProcessVariablesTable = ProcessVariablesTable(self, [], GetProcessVariablesTableColnames())
   732         self.ProcessVariablesTable = ProcessVariablesTable(self, [], GetProcessVariablesTableColnames())
   733         self.ProcessVariablesColSizes = [40, 100, 150, 150, 200]
   733         self.ProcessVariablesColSizes = [40, 100, 150, 150, 200]
   734         self.ProcessVariablesColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
   734         self.ProcessVariablesColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
   735         
   735 
   736         self.ProcessVariablesGrid.SetTable(self.ProcessVariablesTable)
   736         self.ProcessVariablesGrid.SetTable(self.ProcessVariablesTable)
   737         self.ProcessVariablesGrid.SetButtons({"Add": self.AddVariableButton,
   737         self.ProcessVariablesGrid.SetButtons({"Add": self.AddVariableButton,
   738                                               "Delete": self.DeleteVariableButton,
   738                                               "Delete": self.DeleteVariableButton,
   739                                               "Up": self.UpVariableButton,
   739                                               "Up": self.UpVariableButton,
   740                                               "Down": self.DownVariableButton})
   740                                               "Down": self.DownVariableButton})
   741         
   741 
   742         def _AddVariablesElement(new_row):
   742         def _AddVariablesElement(new_row):
   743             self.ProcessVariablesTable.InsertRow(new_row, self.ProcessVariablesDefaultValue.copy())
   743             self.ProcessVariablesTable.InsertRow(new_row, self.ProcessVariablesDefaultValue.copy())
   744             self.SaveProcessVariables()
   744             self.SaveProcessVariables()
   745             self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   745             self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   746             return new_row
   746             return new_row
   747         setattr(self.ProcessVariablesGrid, "_AddRow", _AddVariablesElement)
   747         setattr(self.ProcessVariablesGrid, "_AddRow", _AddVariablesElement)
   748         
   748 
   749         def _DeleteVariablesElement(row):
   749         def _DeleteVariablesElement(row):
   750             self.ProcessVariablesTable.RemoveRow(row)
   750             self.ProcessVariablesTable.RemoveRow(row)
   751             self.SaveProcessVariables()
   751             self.SaveProcessVariables()
   752             self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   752             self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   753         setattr(self.ProcessVariablesGrid, "_DeleteRow", _DeleteVariablesElement)
   753         setattr(self.ProcessVariablesGrid, "_DeleteRow", _DeleteVariablesElement)
   754             
   754 
   755         def _MoveVariablesElement(row, move):
   755         def _MoveVariablesElement(row, move):
   756             new_row = self.ProcessVariablesTable.MoveRow(row, move)
   756             new_row = self.ProcessVariablesTable.MoveRow(row, move)
   757             if new_row != row:
   757             if new_row != row:
   758                 self.SaveProcessVariables()
   758                 self.SaveProcessVariables()
   759                 self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   759                 self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   760             return new_row
   760             return new_row
   761         setattr(self.ProcessVariablesGrid, "_MoveRow", _MoveVariablesElement)
   761         setattr(self.ProcessVariablesGrid, "_MoveRow", _MoveVariablesElement)
   762         
   762 
   763         _refresh_buttons = getattr(self.ProcessVariablesGrid, "RefreshButtons")
   763         _refresh_buttons = getattr(self.ProcessVariablesGrid, "RefreshButtons")
   764         def _RefreshButtons():
   764         def _RefreshButtons():
   765             if self.NodesFilter.GetSelection() == 0:
   765             if self.NodesFilter.GetSelection() == 0:
   766                 _refresh_buttons()
   766                 _refresh_buttons()
   767             else:
   767             else:
   768                 self.AddVariableButton.Enable(False)
   768                 self.AddVariableButton.Enable(False)
   769                 self.DeleteVariableButton.Enable(False)
   769                 self.DeleteVariableButton.Enable(False)
   770                 self.UpVariableButton.Enable(False)
   770                 self.UpVariableButton.Enable(False)
   771                 self.DownVariableButton.Enable(False)
   771                 self.DownVariableButton.Enable(False)
   772         setattr(self.ProcessVariablesGrid, "RefreshButtons", _RefreshButtons)
   772         setattr(self.ProcessVariablesGrid, "RefreshButtons", _RefreshButtons)
   773         
   773 
   774         self.ProcessVariablesGrid.SetRowLabelSize(0)
   774         self.ProcessVariablesGrid.SetRowLabelSize(0)
   775         for col in range(self.ProcessVariablesTable.GetNumberCols()):
   775         for col in range(self.ProcessVariablesTable.GetNumberCols()):
   776             attr = wx.grid.GridCellAttr()
   776             attr = wx.grid.GridCellAttr()
   777             attr.SetAlignment(self.ProcessVariablesColAlignements[col], wx.ALIGN_CENTRE)
   777             attr.SetAlignment(self.ProcessVariablesColAlignements[col], wx.ALIGN_CENTRE)
   778             self.ProcessVariablesGrid.SetColAttr(col, attr)
   778             self.ProcessVariablesGrid.SetColAttr(col, attr)
   779             self.ProcessVariablesGrid.SetColMinimalWidth(col, self.ProcessVariablesColSizes[col])
   779             self.ProcessVariablesGrid.SetColMinimalWidth(col, self.ProcessVariablesColSizes[col])
   780             self.ProcessVariablesGrid.AutoSizeColumn(col, False)
   780             self.ProcessVariablesGrid.AutoSizeColumn(col, False)
   781         self.ProcessVariablesGrid.RefreshButtons()
   781         self.ProcessVariablesGrid.RefreshButtons()
   782     
   782 
   783         self.StartupCommandsDefaultValue = {"Position": 0, "Index": 0, "Subindex": 0, "Value": 0, "Description": ""}
   783         self.StartupCommandsDefaultValue = {"Position": 0, "Index": 0, "Subindex": 0, "Value": 0, "Description": ""}
   784         self.StartupCommandsTable = StartupCommandsTable(self, [], GetStartupCommandsTableColnames())
   784         self.StartupCommandsTable = StartupCommandsTable(self, [], GetStartupCommandsTableColnames())
   785         self.StartupCommandsColSizes = [100, 100, 50, 100, 200]
   785         self.StartupCommandsColSizes = [100, 100, 50, 100, 200]
   786         self.StartupCommandsColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT]
   786         self.StartupCommandsColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT]
   787         
   787 
   788         self.StartupCommandsGrid.SetTable(self.StartupCommandsTable)
   788         self.StartupCommandsGrid.SetTable(self.StartupCommandsTable)
   789         self.StartupCommandsGrid.SetButtons({"Add": self.AddCommandButton,
   789         self.StartupCommandsGrid.SetButtons({"Add": self.AddCommandButton,
   790                                              "Delete": self.DeleteCommandButton})
   790                                              "Delete": self.DeleteCommandButton})
   791         
   791 
   792         def _AddCommandsElement(new_row):
   792         def _AddCommandsElement(new_row):
   793             command = self.StartupCommandsDefaultValue.copy()
   793             command = self.StartupCommandsDefaultValue.copy()
   794             command_idx = self.Controler.AppendStartupCommand(command)
   794             command_idx = self.Controler.AppendStartupCommand(command)
   795             self.RefreshStartupCommands()
   795             self.RefreshStartupCommands()
   796             self.RefreshBuffer()
   796             self.RefreshBuffer()
   797             return self.StartupCommandsTable.GetCommandIndex(command["Position"], command_idx)
   797             return self.StartupCommandsTable.GetCommandIndex(command["Position"], command_idx)
   798         setattr(self.StartupCommandsGrid, "_AddRow", _AddCommandsElement)
   798         setattr(self.StartupCommandsGrid, "_AddRow", _AddCommandsElement)
   799         
   799 
   800         def _DeleteCommandsElement(row):
   800         def _DeleteCommandsElement(row):
   801             command = self.StartupCommandsTable.GetRow(row)
   801             command = self.StartupCommandsTable.GetRow(row)
   802             self.Controler.RemoveStartupCommand(command["Position"], command["command_idx"])
   802             self.Controler.RemoveStartupCommand(command["Position"], command["command_idx"])
   803             self.RefreshStartupCommands()
   803             self.RefreshStartupCommands()
   804             self.RefreshBuffer()
   804             self.RefreshBuffer()
   805         setattr(self.StartupCommandsGrid, "_DeleteRow", _DeleteCommandsElement)
   805         setattr(self.StartupCommandsGrid, "_DeleteRow", _DeleteCommandsElement)
   806         
   806 
   807         self.StartupCommandsGrid.SetRowLabelSize(0)
   807         self.StartupCommandsGrid.SetRowLabelSize(0)
   808         for col in range(self.StartupCommandsTable.GetNumberCols()):
   808         for col in range(self.StartupCommandsTable.GetNumberCols()):
   809             attr = wx.grid.GridCellAttr()
   809             attr = wx.grid.GridCellAttr()
   810             attr.SetAlignment(self.StartupCommandsColAlignements[col], wx.ALIGN_CENTRE)
   810             attr.SetAlignment(self.StartupCommandsColAlignements[col], wx.ALIGN_CENTRE)
   811             self.StartupCommandsGrid.SetColAttr(col, attr)
   811             self.StartupCommandsGrid.SetColAttr(col, attr)
   812             self.StartupCommandsGrid.SetColMinimalWidth(col, self.StartupCommandsColSizes[col])
   812             self.StartupCommandsGrid.SetColMinimalWidth(col, self.StartupCommandsColSizes[col])
   813             self.StartupCommandsGrid.AutoSizeColumn(col, False)
   813             self.StartupCommandsGrid.AutoSizeColumn(col, False)
   814         self.StartupCommandsGrid.RefreshButtons()
   814         self.StartupCommandsGrid.RefreshButtons()
   815     
   815 
   816     def RefreshBuffer(self):
   816     def RefreshBuffer(self):
   817         self.ParentWindow.RefreshTitle()
   817         self.ParentWindow.RefreshTitle()
   818         self.ParentWindow.RefreshFileMenu()
   818         self.ParentWindow.RefreshFileMenu()
   819         self.ParentWindow.RefreshEditMenu()
   819         self.ParentWindow.RefreshEditMenu()
   820         self.ParentWindow.RefreshPageTitles()
   820         self.ParentWindow.RefreshPageTitles()
   821     
   821 
   822     def GetBufferState(self):
   822     def GetBufferState(self):
   823         return self.Controler.GetBufferState()
   823         return self.Controler.GetBufferState()
   824     
   824 
   825     def Undo(self):
   825     def Undo(self):
   826         self.Controler.LoadPrevious()
   826         self.Controler.LoadPrevious()
   827         self.RefreshView()
   827         self.RefreshView()
   828             
   828 
   829     def Redo(self):
   829     def Redo(self):
   830         self.Controler.LoadNext()
   830         self.Controler.LoadNext()
   831         self.RefreshView()
   831         self.RefreshView()
   832     
   832 
   833     def RefreshView(self):
   833     def RefreshView(self):
   834         ConfTreeNodeEditor.RefreshView(self)
   834         ConfTreeNodeEditor.RefreshView(self)
   835         
   835 
   836         self.RefreshNodesFilter()
   836         self.RefreshNodesFilter()
   837         self.RefreshProcessVariables()
   837         self.RefreshProcessVariables()
   838         self.RefreshStartupCommands()
   838         self.RefreshStartupCommands()
   839         self.NodesVariables.RefreshView()
   839         self.NodesVariables.RefreshView()
   840     
   840 
   841     def RefreshNodesFilter(self):
   841     def RefreshNodesFilter(self):
   842         value = self.NodesFilter.GetValue()
   842         value = self.NodesFilter.GetValue()
   843         self.NodesFilter.Clear()
   843         self.NodesFilter.Clear()
   844         self.NodesFilter.Append(_("All"))
   844         self.NodesFilter.Append(_("All"))
   845         self.NodesFilterValues = [{}]
   845         self.NodesFilterValues = [{}]
   855                 int(value)
   855                 int(value)
   856                 self.NodesFilter.SetValue(value)
   856                 self.NodesFilter.SetValue(value)
   857             except Exception:
   857             except Exception:
   858                 self.NodesFilter.SetSelection(0)
   858                 self.NodesFilter.SetSelection(0)
   859         self.RefreshCurrentNodesFilter()
   859         self.RefreshCurrentNodesFilter()
   860     
   860 
   861     def RefreshCurrentNodesFilter(self):
   861     def RefreshCurrentNodesFilter(self):
   862         filter = self.NodesFilter.GetSelection()
   862         filter = self.NodesFilter.GetSelection()
   863         if filter != -1:
   863         if filter != -1:
   864             self.CurrentNodesFilter = self.NodesFilterValues[filter]
   864             self.CurrentNodesFilter = self.NodesFilterValues[filter]
   865         else:
   865         else:
   877                     self.NodesFilter.SetSelection(self.NodesFilterValues.index(self.CurrentNodesFilter))
   877                     self.NodesFilter.SetSelection(self.NodesFilterValues.index(self.CurrentNodesFilter))
   878                 else:
   878                 else:
   879                     self.NodesFilter.SetValue(NODE_POSITION_FILTER_FORMAT % self.CurrentNodesFilter["slave_pos"])
   879                     self.NodesFilter.SetValue(NODE_POSITION_FILTER_FORMAT % self.CurrentNodesFilter["slave_pos"])
   880         self.NodesFilterFirstCharacter = True
   880         self.NodesFilterFirstCharacter = True
   881         self.NodesVariables.SetCurrentNodesFilter(self.CurrentNodesFilter)
   881         self.NodesVariables.SetCurrentNodesFilter(self.CurrentNodesFilter)
   882     
   882 
   883     def RefreshProcessVariables(self):
   883     def RefreshProcessVariables(self):
   884         if self.CurrentNodesFilter is not None:
   884         if self.CurrentNodesFilter is not None:
   885             self.ProcessVariables = self.Controler.GetProcessVariables()
   885             self.ProcessVariables = self.Controler.GetProcessVariables()
   886             slaves = self.Controler.GetSlaves(**self.CurrentNodesFilter)
   886             slaves = self.Controler.GetSlaves(**self.CurrentNodesFilter)
   887             data = []
   887             data = []
   890                     variable["WriteTo"] == "" or variable["WriteTo"][0] in slaves):
   890                     variable["WriteTo"] == "" or variable["WriteTo"][0] in slaves):
   891                     data.append(variable)
   891                     data.append(variable)
   892             self.ProcessVariablesTable.SetData(data)
   892             self.ProcessVariablesTable.SetData(data)
   893             self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   893             self.ProcessVariablesTable.ResetView(self.ProcessVariablesGrid)
   894             self.ProcessVariablesGrid.RefreshButtons()
   894             self.ProcessVariablesGrid.RefreshButtons()
   895     
   895 
   896     def SaveProcessVariables(self):
   896     def SaveProcessVariables(self):
   897         if self.CurrentNodesFilter is not None:
   897         if self.CurrentNodesFilter is not None:
   898             if len(self.CurrentNodesFilter) > 0:
   898             if len(self.CurrentNodesFilter) > 0:
   899                 self.Controler.SetProcessVariables(self.ProcessVariables)
   899                 self.Controler.SetProcessVariables(self.ProcessVariables)
   900             else:
   900             else:
   901                 self.Controler.SetProcessVariables(self.ProcessVariablesTable.GetData())
   901                 self.Controler.SetProcessVariables(self.ProcessVariablesTable.GetData())
   902             self.RefreshBuffer()
   902             self.RefreshBuffer()
   903     
   903 
   904     def RefreshStartupCommands(self, position=None, command_idx=None):
   904     def RefreshStartupCommands(self, position=None, command_idx=None):
   905         if self.CurrentNodesFilter is not None:
   905         if self.CurrentNodesFilter is not None:
   906             col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
   906             col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
   907             self.StartupCommandsTable.SetData(
   907             self.StartupCommandsTable.SetData(
   908                 self.Controler.GetStartupCommands(**self.CurrentNodesFilter))
   908                 self.Controler.GetStartupCommands(**self.CurrentNodesFilter))
   909             self.StartupCommandsTable.ResetView(self.StartupCommandsGrid)
   909             self.StartupCommandsTable.ResetView(self.StartupCommandsGrid)
   910             if position is not None and command_idx is not None:
   910             if position is not None and command_idx is not None:
   911                 self.SelectStartupCommand(position, command_idx, col)
   911                 self.SelectStartupCommand(position, command_idx, col)
   912     
   912 
   913     def SelectStartupCommand(self, position, command_idx, col):
   913     def SelectStartupCommand(self, position, command_idx, col):
   914         self.StartupCommandsGrid.SetSelectedCell(
   914         self.StartupCommandsGrid.SetSelectedCell(
   915             self.StartupCommandsTable.GetCommandIndex(position, command_idx),
   915             self.StartupCommandsTable.GetCommandIndex(position, command_idx),
   916             col)
   916             col)
   917     
   917 
   918     def GetMasterLocation(self):
   918     def GetMasterLocation(self):
   919         return self.Controler.GetCurrentLocation()
   919         return self.Controler.GetCurrentLocation()
   920     
   920 
   921     def AddStartupCommand(self, position, index, subindex):
   921     def AddStartupCommand(self, position, index, subindex):
   922         col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
   922         col = max(self.StartupCommandsGrid.GetGridCursorCol(), 0)
   923         command = self.StartupCommandsDefaultValue.copy()
   923         command = self.StartupCommandsDefaultValue.copy()
   924         command["Position"] = position
   924         command["Position"] = position
   925         command["Index"] = index
   925         command["Index"] = index
   926         command["Subindex"] = subindex
   926         command["Subindex"] = subindex
   927         command_idx = self.Controler.AppendStartupCommand(command)
   927         command_idx = self.Controler.AppendStartupCommand(command)
   928         self.RefreshStartupCommands()
   928         self.RefreshStartupCommands()
   929         self.RefreshBuffer()
   929         self.RefreshBuffer()
   930         self.SelectStartupCommand(position, command_idx, col)
   930         self.SelectStartupCommand(position, command_idx, col)
   931     
   931 
   932     def OnNodesFilterChanged(self, event):
   932     def OnNodesFilterChanged(self, event):
   933         self.RefreshCurrentNodesFilter()
   933         self.RefreshCurrentNodesFilter()
   934         if self.CurrentNodesFilter is not None:
   934         if self.CurrentNodesFilter is not None:
   935             self.RefreshProcessVariables()
   935             self.RefreshProcessVariables()
   936             self.RefreshStartupCommands()
   936             self.RefreshStartupCommands()
   937             self.NodesVariables.RefreshView()
   937             self.NodesVariables.RefreshView()
   938         event.Skip()
   938         event.Skip()
   939     
   939 
   940     def OnNodesFilterKeyDown(self, event):
   940     def OnNodesFilterKeyDown(self, event):
   941         if self.NodesFilterFirstCharacter:
   941         if self.NodesFilterFirstCharacter:
   942             keycode = event.GetKeyCode()
   942             keycode = event.GetKeyCode()
   943             if keycode not in [wx.WXK_RETURN, 
   943             if keycode not in [wx.WXK_RETURN,
   944                                wx.WXK_NUMPAD_ENTER]:
   944                                wx.WXK_NUMPAD_ENTER]:
   945                 self.NodesFilterFirstCharacter = False
   945                 self.NodesFilterFirstCharacter = False
   946                 if keycode not in NAVIGATION_KEYS:
   946                 if keycode not in NAVIGATION_KEYS:
   947                     self.NodesFilter.SetValue("")
   947                     self.NodesFilter.SetValue("")
   948             if keycode not in [wx.WXK_DELETE, 
   948             if keycode not in [wx.WXK_DELETE,
   949                                wx.WXK_NUMPAD_DELETE, 
   949                                wx.WXK_NUMPAD_DELETE,
   950                                wx.WXK_BACK]:
   950                                wx.WXK_BACK]:
   951                 event.Skip()
   951                 event.Skip()
   952         else:
   952         else:
   953             event.Skip()
   953             event.Skip()
   954     
   954 
   955     def OnProcessVariablesGridCellChange(self, event):
   955     def OnProcessVariablesGridCellChange(self, event):
   956         row, col = event.GetRow(), event.GetCol()
   956         row, col = event.GetRow(), event.GetCol()
   957         colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
   957         colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
   958         value = self.ProcessVariablesTable.GetValue(row, col)
   958         value = self.ProcessVariablesTable.GetValue(row, col)
   959         message = None
   959         message = None
   971         else:
   971         else:
   972             dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
   972             dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
   973             dialog.ShowModal()
   973             dialog.ShowModal()
   974             dialog.Destroy()
   974             dialog.Destroy()
   975             event.Veto()
   975             event.Veto()
   976     
   976 
   977     def OnProcessVariablesGridCellLeftClick(self, event):
   977     def OnProcessVariablesGridCellLeftClick(self, event):
   978         row = event.GetRow()
   978         row = event.GetRow()
   979         if event.GetCol() == 0:
   979         if event.GetCol() == 0:
   980             var_name = self.ProcessVariablesTable.GetValueByName(row, "Name")
   980             var_name = self.ProcessVariablesTable.GetValueByName(row, "Name")
   981             var_type = self.Controler.GetSlaveVariableDataType(
   981             var_type = self.Controler.GetSlaveVariableDataType(
   982                 *self.ProcessVariablesTable.GetValueByName(row, "ReadFrom"))
   982                 *self.ProcessVariablesTable.GetValueByName(row, "ReadFrom"))
   983             data_size = self.Controler.GetSizeOfType(var_type)
   983             data_size = self.Controler.GetSizeOfType(var_type)
   984             number = self.ProcessVariablesTable.GetValueByName(row, "Number")
   984             number = self.ProcessVariablesTable.GetValueByName(row, "Number")
   985             location = "%%M%s" % data_size + \
   985             location = "%%M%s" % data_size + \
   986                        ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + (number,)))
   986                        ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + (number,)))
   987             
   987 
   988             data = wx.TextDataObject(str((location, "location", var_type, var_name, "")))
   988             data = wx.TextDataObject(str((location, "location", var_type, var_name, "")))
   989             dragSource = wx.DropSource(self.ProcessVariablesGrid)
   989             dragSource = wx.DropSource(self.ProcessVariablesGrid)
   990             dragSource.SetData(data)
   990             dragSource.SetData(data)
   991             dragSource.DoDragDrop()
   991             dragSource.DoDragDrop()
   992         event.Skip()
   992         event.Skip()
   993     
   993 
   994     def OnProcessVariablesGridKeyDown(self, event):
   994     def OnProcessVariablesGridKeyDown(self, event):
   995         keycode = event.GetKeyCode()
   995         keycode = event.GetKeyCode()
   996         col = self.ProcessVariablesGrid.GetGridCursorCol()
   996         col = self.ProcessVariablesGrid.GetGridCursorCol()
   997         row = self.ProcessVariablesGrid.GetGridCursorRow()
   997         row = self.ProcessVariablesGrid.GetGridCursorRow()
   998         colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
   998         colname = self.ProcessVariablesTable.GetColLabelValue(col, False)
   999         if (keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and 
   999         if (keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and
  1000             (colname.startswith("Read from") or colname.startswith("Write to"))):
  1000             (colname.startswith("Read from") or colname.startswith("Write to"))):
  1001             self.ProcessVariablesTable.SetValue(row, col, "")
  1001             self.ProcessVariablesTable.SetValue(row, col, "")
  1002             self.SaveProcessVariables()
  1002             self.SaveProcessVariables()
  1003             wx.CallAfter(self.ProcessVariablesTable.ResetView, self.ProcessVariablesGrid)
  1003             wx.CallAfter(self.ProcessVariablesTable.ResetView, self.ProcessVariablesGrid)
  1004         else:
  1004         else:
  1005             event.Skip()
  1005             event.Skip()
  1006     
  1006 
  1007     def OnStartupCommandsGridEditorShow(self, event):
  1007     def OnStartupCommandsGridEditorShow(self, event):
  1008         self.CellShown = event.GetRow(), event.GetCol()
  1008         self.CellShown = event.GetRow(), event.GetCol()
  1009         event.Skip()
  1009         event.Skip()
  1010     
  1010 
  1011     def OnStartupCommandsGridCellChange(self, event):
  1011     def OnStartupCommandsGridCellChange(self, event):
  1012         row, col = event.GetRow(), event.GetCol()
  1012         row, col = event.GetRow(), event.GetCol()
  1013         if self.CellShown == (row, col):
  1013         if self.CellShown == (row, col):
  1014             self.CellShown = None
  1014             self.CellShown = None
  1015             colname = self.StartupCommandsTable.GetColLabelValue(col, False)
  1015             colname = self.StartupCommandsTable.GetColLabelValue(col, False)
  1027                     command_idx = self.Controler.AppendStartupCommand(command)
  1027                     command_idx = self.Controler.AppendStartupCommand(command)
  1028                     wx.CallAfter(self.RefreshStartupCommands, command["Position"], command_idx)
  1028                     wx.CallAfter(self.RefreshStartupCommands, command["Position"], command_idx)
  1029             else:
  1029             else:
  1030                 command = self.StartupCommandsTable.GetRow(row)
  1030                 command = self.StartupCommandsTable.GetRow(row)
  1031                 self.Controler.SetStartupCommandInfos(command)
  1031                 self.Controler.SetStartupCommandInfos(command)
  1032                 if colname in ["Index", "SubIndex"]: 
  1032                 if colname in ["Index", "SubIndex"]:
  1033                     wx.CallAfter(self.RefreshStartupCommands, command["Position"], command["command_idx"])
  1033                     wx.CallAfter(self.RefreshStartupCommands, command["Position"], command["command_idx"])
  1034             if message is None:
  1034             if message is None:
  1035                 self.RefreshBuffer()
  1035                 self.RefreshBuffer()
  1036                 event.Skip()
  1036                 event.Skip()
  1037             else:
  1037             else:
  1039                 dialog.ShowModal()
  1039                 dialog.ShowModal()
  1040                 dialog.Destroy()
  1040                 dialog.Destroy()
  1041                 event.Veto()
  1041                 event.Veto()
  1042         else:
  1042         else:
  1043             event.Veto()
  1043             event.Veto()
  1044     
  1044 
  1045     def OnResize(self, event):
  1045     def OnResize(self, event):
  1046         self.EthercatMasterEditor.GetBestSize()
  1046         self.EthercatMasterEditor.GetBestSize()
  1047         xstart, ystart = self.EthercatMasterEditor.GetViewStart()
  1047         xstart, ystart = self.EthercatMasterEditor.GetViewStart()
  1048         window_size = self.EthercatMasterEditor.GetClientSize()
  1048         window_size = self.EthercatMasterEditor.GetClientSize()
  1049         maxx, maxy = self.EthercatMasterEditorSizer.GetMinSize()
  1049         maxx, maxy = self.EthercatMasterEditorSizer.GetMinSize()
  1050         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
  1050         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
  1051         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
  1051         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
  1052         self.EthercatMasterEditor.Scroll(posx, posy)
  1052         self.EthercatMasterEditor.Scroll(posx, posy)
  1053         self.EthercatMasterEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
  1053         self.EthercatMasterEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
  1054                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
  1054                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
  1055         event.Skip()
  1055         event.Skip()
  1056         
  1056 
  1057     #def OnButtonClick(self, event):
  1057     #def OnButtonClick(self, event):
  1058     #    self.MasterState = self.Controler.getMasterState()
  1058     #    self.MasterState = self.Controler.getMasterState()
  1059     #    if self.MasterState:
  1059     #    if self.MasterState:
  1060     #        self.Phase.SetValue(self.MasterState["phase"])
  1060     #        self.Phase.SetValue(self.MasterState["phase"])
  1061     #        self.Active.SetValue(self.MasterState["active"])
  1061     #        self.Active.SetValue(self.MasterState["active"])
  1065     #        self.TxFrames.SetValue(self.MasterState["TXframe"])
  1065     #        self.TxFrames.SetValue(self.MasterState["TXframe"])
  1066     #        self.RxFrames.SetValue(self.MasterState["RXframe"])
  1066     #        self.RxFrames.SetValue(self.MasterState["RXframe"])
  1067     #        self.TxByte.SetValue(self.MasterState["TXbyte"])
  1067     #        self.TxByte.SetValue(self.MasterState["TXbyte"])
  1068     #        self.TxError.SetValue(self.MasterState["TXerror"])
  1068     #        self.TxError.SetValue(self.MasterState["TXerror"])
  1069     #        self.LostFrames.SetValue(self.MasterState["lost"])
  1069     #        self.LostFrames.SetValue(self.MasterState["lost"])
  1070             
  1070 
  1071     #        self.TxFrameRate1.SetValue(self.MasterState["TXframerate1"])
  1071     #        self.TxFrameRate1.SetValue(self.MasterState["TXframerate1"])
  1072     #        self.TxFrameRate2.SetValue(self.MasterState["TXframerate2"])
  1072     #        self.TxFrameRate2.SetValue(self.MasterState["TXframerate2"])
  1073     #        self.TxFrameRate3.SetValue(self.MasterState["TXframerate3"])
  1073     #        self.TxFrameRate3.SetValue(self.MasterState["TXframerate3"])
  1074     #        self.TxRate1.SetValue(self.MasterState["TXrate1"])
  1074     #        self.TxRate1.SetValue(self.MasterState["TXrate1"])
  1075     #        self.TxRate2.SetValue(self.MasterState["TXrate2"])
  1075     #        self.TxRate2.SetValue(self.MasterState["TXrate2"])
  1078     #        self.LossRate2.SetValue(self.MasterState["loss2"])
  1078     #        self.LossRate2.SetValue(self.MasterState["loss2"])
  1079     #        self.LossRate3.SetValue(self.MasterState["loss3"])
  1079     #        self.LossRate3.SetValue(self.MasterState["loss3"])
  1080     #        self.FrameLoss1.SetValue(self.MasterState["frameloss1"])
  1080     #        self.FrameLoss1.SetValue(self.MasterState["frameloss1"])
  1081     #        self.FrameLoss2.SetValue(self.MasterState["frameloss2"])
  1081     #        self.FrameLoss2.SetValue(self.MasterState["frameloss2"])
  1082     #        self.FrameLoss3.SetValue(self.MasterState["frameloss3"])
  1082     #        self.FrameLoss3.SetValue(self.MasterState["frameloss3"])
  1083     
  1083 
  1084 class LibraryEditorSizer(wx.FlexGridSizer):
  1084 class LibraryEditorSizer(wx.FlexGridSizer):
  1085     
  1085 
  1086     def __init__(self, parent, module_library, buttons):
  1086     def __init__(self, parent, module_library, buttons):
  1087         wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=4, vgap=5)
  1087         wx.FlexGridSizer.__init__(self, cols=1, hgap=0, rows=4, vgap=5)
  1088         
  1088 
  1089         self.ModuleLibrary = module_library
  1089         self.ModuleLibrary = module_library
  1090         self.ParentWindow = parent
  1090         self.ParentWindow = parent
  1091         
  1091 
  1092         self.AddGrowableCol(0)
  1092         self.AddGrowableCol(0)
  1093         self.AddGrowableRow(1)
  1093         self.AddGrowableRow(1)
  1094         self.AddGrowableRow(3)
  1094         self.AddGrowableRow(3)
  1095         
  1095 
  1096         ESI_files_label = wx.StaticText(parent, 
  1096         ESI_files_label = wx.StaticText(parent,
  1097             label=_("ESI Files:"))
  1097             label=_("ESI Files:"))
  1098         self.AddWindow(ESI_files_label, border=10, 
  1098         self.AddWindow(ESI_files_label, border=10,
  1099             flag=wx.TOP|wx.LEFT|wx.RIGHT)
  1099             flag=wx.TOP|wx.LEFT|wx.RIGHT)
  1100         
  1100 
  1101         folder_tree_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=0)
  1101         folder_tree_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=0)
  1102         folder_tree_sizer.AddGrowableCol(0)
  1102         folder_tree_sizer.AddGrowableCol(0)
  1103         folder_tree_sizer.AddGrowableRow(0)
  1103         folder_tree_sizer.AddGrowableRow(0)
  1104         self.AddSizer(folder_tree_sizer, border=10, 
  1104         self.AddSizer(folder_tree_sizer, border=10,
  1105             flag=wx.GROW|wx.LEFT|wx.RIGHT)
  1105             flag=wx.GROW|wx.LEFT|wx.RIGHT)
  1106         
  1106 
  1107         self.ESIFiles = FolderTree(parent, self.GetPath(), editable=False)
  1107         self.ESIFiles = FolderTree(parent, self.GetPath(), editable=False)
  1108         self.ESIFiles.SetFilter(".xml")
  1108         self.ESIFiles.SetFilter(".xml")
  1109         folder_tree_sizer.AddWindow(self.ESIFiles, flag=wx.GROW)
  1109         folder_tree_sizer.AddWindow(self.ESIFiles, flag=wx.GROW)
  1110         
  1110 
  1111         buttons_sizer = wx.BoxSizer(wx.VERTICAL)
  1111         buttons_sizer = wx.BoxSizer(wx.VERTICAL)
  1112         folder_tree_sizer.AddSizer(buttons_sizer, 
  1112         folder_tree_sizer.AddSizer(buttons_sizer,
  1113             flag=wx.ALIGN_CENTER_VERTICAL)
  1113             flag=wx.ALIGN_CENTER_VERTICAL)
  1114         
  1114 
  1115         for idx, (name, bitmap, help, callback) in enumerate(buttons):
  1115         for idx, (name, bitmap, help, callback) in enumerate(buttons):
  1116             button = wx.lib.buttons.GenBitmapButton(parent, 
  1116             button = wx.lib.buttons.GenBitmapButton(parent,
  1117                   bitmap=GetBitmap(bitmap), 
  1117                   bitmap=GetBitmap(bitmap),
  1118                   size=wx.Size(28, 28), style=wx.NO_BORDER)
  1118                   size=wx.Size(28, 28), style=wx.NO_BORDER)
  1119             button.SetToolTipString(help)
  1119             button.SetToolTipString(help)
  1120             setattr(self, name, button)
  1120             setattr(self, name, button)
  1121             if idx > 0:
  1121             if idx > 0:
  1122                 flag = wx.TOP
  1122                 flag = wx.TOP
  1125             if callback is None:
  1125             if callback is None:
  1126                 callback = getattr(self, "On" + name, None)
  1126                 callback = getattr(self, "On" + name, None)
  1127             if callback is not None:
  1127             if callback is not None:
  1128                 parent.Bind(wx.EVT_BUTTON, callback, button)
  1128                 parent.Bind(wx.EVT_BUTTON, callback, button)
  1129             buttons_sizer.AddWindow(button, border=10, flag=flag)
  1129             buttons_sizer.AddWindow(button, border=10, flag=flag)
  1130         
  1130 
  1131         modules_label = wx.StaticText(parent, 
  1131         modules_label = wx.StaticText(parent,
  1132             label=_("Modules library:"))
  1132             label=_("Modules library:"))
  1133         self.AddSizer(modules_label, border=10, 
  1133         self.AddSizer(modules_label, border=10,
  1134             flag=wx.LEFT|wx.RIGHT)
  1134             flag=wx.LEFT|wx.RIGHT)
  1135         
  1135 
  1136         self.ModulesGrid = wx.gizmos.TreeListCtrl(parent,
  1136         self.ModulesGrid = wx.gizmos.TreeListCtrl(parent,
  1137               style=wx.TR_DEFAULT_STYLE |
  1137               style=wx.TR_DEFAULT_STYLE |
  1138                     wx.TR_ROW_LINES |
  1138                     wx.TR_ROW_LINES |
  1139                     wx.TR_COLUMN_LINES |
  1139                     wx.TR_COLUMN_LINES |
  1140                     wx.TR_HIDE_ROOT |
  1140                     wx.TR_HIDE_ROOT |
  1143             self.OnModulesGridLeftDown)
  1143             self.OnModulesGridLeftDown)
  1144         self.ModulesGrid.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT,
  1144         self.ModulesGrid.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT,
  1145             self.OnModulesGridBeginLabelEdit)
  1145             self.OnModulesGridBeginLabelEdit)
  1146         self.ModulesGrid.Bind(wx.EVT_TREE_END_LABEL_EDIT,
  1146         self.ModulesGrid.Bind(wx.EVT_TREE_END_LABEL_EDIT,
  1147             self.OnModulesGridEndLabelEdit)
  1147             self.OnModulesGridEndLabelEdit)
  1148         self.ModulesGrid.GetHeaderWindow().Bind(wx.EVT_MOTION, 
  1148         self.ModulesGrid.GetHeaderWindow().Bind(wx.EVT_MOTION,
  1149             self.OnModulesGridHeaderMotion)
  1149             self.OnModulesGridHeaderMotion)
  1150         self.AddWindow(self.ModulesGrid, border=10, 
  1150         self.AddWindow(self.ModulesGrid, border=10,
  1151             flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
  1151             flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
  1152         
  1152 
  1153         for colname, colsize, colalign in zip(
  1153         for colname, colsize, colalign in zip(
  1154                 [_("Name")] + [param_infos["column_label"] 
  1154                 [_("Name")] + [param_infos["column_label"]
  1155                                for param, param_infos in 
  1155                                for param, param_infos in
  1156                                self.ModuleLibrary.MODULES_EXTRA_PARAMS],
  1156                                self.ModuleLibrary.MODULES_EXTRA_PARAMS],
  1157                 [400] + [param_infos["column_size"] 
  1157                 [400] + [param_infos["column_size"]
  1158                          for param, param_infos in 
  1158                          for param, param_infos in
  1159                          self.ModuleLibrary.MODULES_EXTRA_PARAMS],
  1159                          self.ModuleLibrary.MODULES_EXTRA_PARAMS],
  1160                 [wx.ALIGN_LEFT] + [wx.ALIGN_RIGHT] * len(self.ModuleLibrary.MODULES_EXTRA_PARAMS)):
  1160                 [wx.ALIGN_LEFT] + [wx.ALIGN_RIGHT] * len(self.ModuleLibrary.MODULES_EXTRA_PARAMS)):
  1161             self.ModulesGrid.AddColumn(_(colname), colsize, colalign, edit=True)
  1161             self.ModulesGrid.AddColumn(_(colname), colsize, colalign, edit=True)
  1162         self.ModulesGrid.SetMainColumn(0)
  1162         self.ModulesGrid.SetMainColumn(0)
  1163         
  1163 
  1164         self.CurrentSelectedCol = None
  1164         self.CurrentSelectedCol = None
  1165         self.LastToolTipCol = None
  1165         self.LastToolTipCol = None
  1166     
  1166 
  1167     def GetPath(self):
  1167     def GetPath(self):
  1168         return self.ModuleLibrary.GetPath()
  1168         return self.ModuleLibrary.GetPath()
  1169     
  1169 
  1170     def SetControlMinSize(self, size):
  1170     def SetControlMinSize(self, size):
  1171         self.ESIFiles.SetMinSize(size)
  1171         self.ESIFiles.SetMinSize(size)
  1172         self.ModulesGrid.SetMinSize(size)
  1172         self.ModulesGrid.SetMinSize(size)
  1173         
  1173 
  1174     def GetSelectedFilePath(self):
  1174     def GetSelectedFilePath(self):
  1175         return self.ESIFiles.GetPath()
  1175         return self.ESIFiles.GetPath()
  1176     
  1176 
  1177     def RefreshView(self):
  1177     def RefreshView(self):
  1178         self.ESIFiles.RefreshTree()
  1178         self.ESIFiles.RefreshTree()
  1179         self.RefreshModulesGrid()
  1179         self.RefreshModulesGrid()
  1180     
  1180 
  1181     def RefreshModulesGrid(self):
  1181     def RefreshModulesGrid(self):
  1182         root = self.ModulesGrid.GetRootItem()
  1182         root = self.ModulesGrid.GetRootItem()
  1183         if not root.IsOk():
  1183         if not root.IsOk():
  1184             root = self.ModulesGrid.AddRoot("Modules")
  1184             root = self.ModulesGrid.AddRoot("Modules")
  1185         self.GenerateModulesGridBranch(root, 
  1185         self.GenerateModulesGridBranch(root,
  1186             self.ModuleLibrary.GetModulesLibrary(), 
  1186             self.ModuleLibrary.GetModulesLibrary(),
  1187             GetVariablesTableColnames())
  1187             GetVariablesTableColnames())
  1188         self.ModulesGrid.Expand(root)
  1188         self.ModulesGrid.Expand(root)
  1189             
  1189 
  1190     def GenerateModulesGridBranch(self, root, modules, colnames):
  1190     def GenerateModulesGridBranch(self, root, modules, colnames):
  1191         item, root_cookie = self.ModulesGrid.GetFirstChild(root)
  1191         item, root_cookie = self.ModulesGrid.GetFirstChild(root)
  1192         
  1192 
  1193         no_more_items = not item.IsOk()
  1193         no_more_items = not item.IsOk()
  1194         for module in modules:
  1194         for module in modules:
  1195             if no_more_items:
  1195             if no_more_items:
  1196                 item = self.ModulesGrid.AppendItem(root, "")
  1196                 item = self.ModulesGrid.AppendItem(root, "")
  1197             self.ModulesGrid.SetItemText(item, module["name"], 0)
  1197             self.ModulesGrid.SetItemText(item, module["name"], 0)
  1198             if module["infos"] is not None:
  1198             if module["infos"] is not None:
  1199                 for param_idx, (param, param_infos) in enumerate(self.ModuleLibrary.MODULES_EXTRA_PARAMS):
  1199                 for param_idx, (param, param_infos) in enumerate(self.ModuleLibrary.MODULES_EXTRA_PARAMS):
  1200                     self.ModulesGrid.SetItemText(item, 
  1200                     self.ModulesGrid.SetItemText(item,
  1201                                                  str(module["infos"][param]), 
  1201                                                  str(module["infos"][param]),
  1202                                                  param_idx + 1)
  1202                                                  param_idx + 1)
  1203             else:
  1203             else:
  1204                 self.ModulesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY)
  1204                 self.ModulesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY)
  1205             self.ModulesGrid.SetItemPyData(item, module["infos"])
  1205             self.ModulesGrid.SetItemPyData(item, module["infos"])
  1206             self.GenerateModulesGridBranch(item, module["children"], colnames)
  1206             self.GenerateModulesGridBranch(item, module["children"], colnames)
  1207             if not no_more_items:
  1207             if not no_more_items:
  1208                 item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
  1208                 item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
  1209                 no_more_items = not item.IsOk()
  1209                 no_more_items = not item.IsOk()
  1210         
  1210 
  1211         if not no_more_items:
  1211         if not no_more_items:
  1212             to_delete = []
  1212             to_delete = []
  1213             while item.IsOk():
  1213             while item.IsOk():
  1214                 to_delete.append(item)
  1214                 to_delete.append(item)
  1215                 item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
  1215                 item, root_cookie = self.ModulesGrid.GetNextChild(root, root_cookie)
  1216             for item in to_delete:
  1216             for item in to_delete:
  1217                 self.ModulesGrid.Delete(item)
  1217                 self.ModulesGrid.Delete(item)
  1218     
  1218 
  1219     def OnImportButton(self, event):
  1219     def OnImportButton(self, event):
  1220         dialog = wx.FileDialog(self.ParentWindow,
  1220         dialog = wx.FileDialog(self.ParentWindow,
  1221              _("Choose an XML file"), 
  1221              _("Choose an XML file"),
  1222              os.getcwd(), "",  
  1222              os.getcwd(), "",
  1223              _("XML files (*.xml)|*.xml|All files|*.*"), wx.OPEN)
  1223              _("XML files (*.xml)|*.xml|All files|*.*"), wx.OPEN)
  1224         
  1224 
  1225         if dialog.ShowModal() == wx.ID_OK:
  1225         if dialog.ShowModal() == wx.ID_OK:
  1226             filepath = dialog.GetPath()
  1226             filepath = dialog.GetPath()
  1227             if self.ModuleLibrary.ImportModuleLibrary(filepath):
  1227             if self.ModuleLibrary.ImportModuleLibrary(filepath):
  1228                 wx.CallAfter(self.RefreshView)
  1228                 wx.CallAfter(self.RefreshView)
  1229             else:
  1229             else:
  1230                 message = wx.MessageDialog(self, 
  1230                 message = wx.MessageDialog(self,
  1231                     _("No such XML file: %s\n") % filepath, 
  1231                     _("No such XML file: %s\n") % filepath,
  1232                     _("Error"), wx.OK|wx.ICON_ERROR)
  1232                     _("Error"), wx.OK|wx.ICON_ERROR)
  1233                 message.ShowModal()
  1233                 message.ShowModal()
  1234                 message.Destroy()
  1234                 message.Destroy()
  1235         dialog.Destroy()
  1235         dialog.Destroy()
  1236         
  1236 
  1237         event.Skip()
  1237         event.Skip()
  1238     
  1238 
  1239     def OnDeleteButton(self, event):
  1239     def OnDeleteButton(self, event):
  1240         filepath = self.GetSelectedFilePath()
  1240         filepath = self.GetSelectedFilePath()
  1241         if os.path.isfile(filepath):
  1241         if os.path.isfile(filepath):
  1242             folder, filename = os.path.split(filepath)
  1242             folder, filename = os.path.split(filepath)
  1243             
  1243 
  1244             dialog = wx.MessageDialog(self.ParentWindow, 
  1244             dialog = wx.MessageDialog(self.ParentWindow,
  1245                   _("Do you really want to delete the file '%s'?") % filename, 
  1245                   _("Do you really want to delete the file '%s'?") % filename,
  1246                   _("Delete File"), wx.YES_NO|wx.ICON_QUESTION)
  1246                   _("Delete File"), wx.YES_NO|wx.ICON_QUESTION)
  1247             remove = dialog.ShowModal() == wx.ID_YES
  1247             remove = dialog.ShowModal() == wx.ID_YES
  1248             dialog.Destroy()
  1248             dialog.Destroy()
  1249             
  1249 
  1250             if remove:
  1250             if remove:
  1251                 os.remove(filepath)
  1251                 os.remove(filepath)
  1252                 self.ModuleLibrary.LoadModules()
  1252                 self.ModuleLibrary.LoadModules()
  1253                 wx.CallAfter(self.RefreshView)
  1253                 wx.CallAfter(self.RefreshView)
  1254         event.Skip()
  1254         event.Skip()
  1255     
  1255 
  1256     def OnModulesGridLeftDown(self, event):
  1256     def OnModulesGridLeftDown(self, event):
  1257         item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
  1257         item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
  1258         if item.IsOk():
  1258         if item.IsOk():
  1259             entry_infos = self.ModulesGrid.GetItemPyData(item)
  1259             entry_infos = self.ModulesGrid.GetItemPyData(item)
  1260             if entry_infos is not None and col > 0:
  1260             if entry_infos is not None and col > 0:
  1291                         param,
  1291                         param,
  1292                         int(event.GetLabel()))
  1292                         int(event.GetLabel()))
  1293                     wx.CallAfter(self.RefreshModulesGrid)
  1293                     wx.CallAfter(self.RefreshModulesGrid)
  1294                     event.Skip()
  1294                     event.Skip()
  1295                 except ValueError:
  1295                 except ValueError:
  1296                     message = wx.MessageDialog(self, 
  1296                     message = wx.MessageDialog(self,
  1297                         _("Module %s must be an integer!") % stripped_column_label, 
  1297                         _("Module %s must be an integer!") % stripped_column_label,
  1298                         _("Error"), wx.OK|wx.ICON_ERROR)
  1298                         _("Error"), wx.OK|wx.ICON_ERROR)
  1299                     message.ShowModal()
  1299                     message.ShowModal()
  1300                     message.Destroy()
  1300                     message.Destroy()
  1301                     event.Veto()
  1301                     event.Veto()
  1302             else:
  1302             else:
  1303                 event.Veto()
  1303                 event.Veto()
  1304         else:
  1304         else:
  1305             event.Veto()
  1305             event.Veto()
  1306                 
  1306 
  1307     def OnModulesGridHeaderMotion(self, event):
  1307     def OnModulesGridHeaderMotion(self, event):
  1308         item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
  1308         item, flags, col = self.ModulesGrid.HitTest(event.GetPosition())
  1309         if col != self.LastToolTipCol and self.LastToolTipCol is not None:
  1309         if col != self.LastToolTipCol and self.LastToolTipCol is not None:
  1310             self.ModulesGrid.GetHeaderWindow().SetToolTip(None)
  1310             self.ModulesGrid.GetHeaderWindow().SetToolTip(None)
  1311             self.LastToolTipCol = None
  1311             self.LastToolTipCol = None
  1312         if col > 0 and self.LastToolTipCol != col:
  1312         if col > 0 and self.LastToolTipCol != col:
  1313             self.LastToolTipCol = col
  1313             self.LastToolTipCol = col
  1314             param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[col - 1]
  1314             param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[col - 1]
  1315             wx.CallAfter(self.ModulesGrid.GetHeaderWindow().SetToolTipString, 
  1315             wx.CallAfter(self.ModulesGrid.GetHeaderWindow().SetToolTipString,
  1316                          param_infos["description"])
  1316                          param_infos["description"])
  1317         event.Skip()
  1317         event.Skip()
  1318 
  1318 
  1319 class DatabaseManagementDialog(wx.Dialog):
  1319 class DatabaseManagementDialog(wx.Dialog):
  1320     
  1320 
  1321     def __init__(self, parent, database):
  1321     def __init__(self, parent, database):
  1322         wx.Dialog.__init__(self, parent,
  1322         wx.Dialog.__init__(self, parent,
  1323               size=wx.Size(700, 500), title=_('ESI Files Database management'),
  1323               size=wx.Size(700, 500), title=_('ESI Files Database management'),
  1324               style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
  1324               style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
  1325         
  1325 
  1326         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
  1326         main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
  1327         main_sizer.AddGrowableCol(0)
  1327         main_sizer.AddGrowableCol(0)
  1328         main_sizer.AddGrowableRow(0)
  1328         main_sizer.AddGrowableRow(0)
  1329         
  1329 
  1330         self.DatabaseSizer = LibraryEditorSizer(self, database,
  1330         self.DatabaseSizer = LibraryEditorSizer(self, database,
  1331             [("ImportButton", "ImportESI", _("Import file to ESI files database"), None),
  1331             [("ImportButton", "ImportESI", _("Import file to ESI files database"), None),
  1332              ("DeleteButton", "remove_element", _("Remove file from database"), None)])
  1332              ("DeleteButton", "remove_element", _("Remove file from database"), None)])
  1333         self.DatabaseSizer.SetControlMinSize(wx.Size(0, 0))
  1333         self.DatabaseSizer.SetControlMinSize(wx.Size(0, 0))
  1334         main_sizer.AddSizer(self.DatabaseSizer, border=10,
  1334         main_sizer.AddSizer(self.DatabaseSizer, border=10,
  1335             flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
  1335             flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
  1336         
  1336 
  1337         button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
  1337         button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
  1338         button_sizer.GetAffirmativeButton().SetLabel(_("Add file to project"))
  1338         button_sizer.GetAffirmativeButton().SetLabel(_("Add file to project"))
  1339         button_sizer.GetCancelButton().SetLabel(_("Close"))
  1339         button_sizer.GetCancelButton().SetLabel(_("Close"))
  1340         main_sizer.AddSizer(button_sizer, border=10, 
  1340         main_sizer.AddSizer(button_sizer, border=10,
  1341               flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
  1341               flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
  1342         
  1342 
  1343         self.SetSizer(main_sizer)
  1343         self.SetSizer(main_sizer)
  1344         
  1344 
  1345         self.DatabaseSizer.RefreshView()
  1345         self.DatabaseSizer.RefreshView()
  1346         
  1346 
  1347     def GetValue(self):
  1347     def GetValue(self):
  1348         return self.DatabaseSizer.GetSelectedFilePath()
  1348         return self.DatabaseSizer.GetSelectedFilePath()
  1349 
  1349 
  1350 class LibraryEditor(ConfTreeNodeEditor):
  1350 class LibraryEditor(ConfTreeNodeEditor):
  1351     
  1351 
  1352     CONFNODEEDITOR_TABS = [
  1352     CONFNODEEDITOR_TABS = [
  1353         (_("Modules Library"), "_create_ModuleLibraryEditor")]
  1353         (_("Modules Library"), "_create_ModuleLibraryEditor")]
  1354     
  1354 
  1355     def _create_ModuleLibraryEditor(self, prnt):
  1355     def _create_ModuleLibraryEditor(self, prnt):
  1356         self.ModuleLibraryEditor = wx.ScrolledWindow(prnt,
  1356         self.ModuleLibraryEditor = wx.ScrolledWindow(prnt,
  1357             style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
  1357             style=wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL)
  1358         self.ModuleLibraryEditor.Bind(wx.EVT_SIZE, self.OnResize)
  1358         self.ModuleLibraryEditor.Bind(wx.EVT_SIZE, self.OnResize)
  1359         
  1359 
  1360         self.ModuleLibrarySizer = LibraryEditorSizer(self.ModuleLibraryEditor,
  1360         self.ModuleLibrarySizer = LibraryEditorSizer(self.ModuleLibraryEditor,
  1361             self.Controler.GetModulesLibraryInstance(),
  1361             self.Controler.GetModulesLibraryInstance(),
  1362             [("ImportButton", "ImportESI", _("Import ESI file"), None),
  1362             [("ImportButton", "ImportESI", _("Import ESI file"), None),
  1363              ("AddButton", "ImportDatabase", _("Add file from ESI files database"), self.OnAddButton),
  1363              ("AddButton", "ImportDatabase", _("Add file from ESI files database"), self.OnAddButton),
  1364              ("DeleteButton", "remove_element", _("Remove file from library"), None)])
  1364              ("DeleteButton", "remove_element", _("Remove file from library"), None)])
  1365         self.ModuleLibrarySizer.SetControlMinSize(wx.Size(0, 200))
  1365         self.ModuleLibrarySizer.SetControlMinSize(wx.Size(0, 200))
  1366         self.ModuleLibraryEditor.SetSizer(self.ModuleLibrarySizer)
  1366         self.ModuleLibraryEditor.SetSizer(self.ModuleLibrarySizer)
  1367         
  1367 
  1368         return self.ModuleLibraryEditor
  1368         return self.ModuleLibraryEditor
  1369 
  1369 
  1370     def __init__(self, parent, controler, window):
  1370     def __init__(self, parent, controler, window):
  1371         ConfTreeNodeEditor.__init__(self, parent, controler, window)
  1371         ConfTreeNodeEditor.__init__(self, parent, controler, window)
  1372     
  1372 
  1373         self.RefreshView()
  1373         self.RefreshView()
  1374     
  1374 
  1375     def RefreshView(self):
  1375     def RefreshView(self):
  1376         ConfTreeNodeEditor.RefreshView(self)
  1376         ConfTreeNodeEditor.RefreshView(self)
  1377         self.ModuleLibrarySizer.RefreshView()
  1377         self.ModuleLibrarySizer.RefreshView()
  1378 
  1378 
  1379     def OnAddButton(self, event):
  1379     def OnAddButton(self, event):
  1380         dialog = DatabaseManagementDialog(self, 
  1380         dialog = DatabaseManagementDialog(self,
  1381             self.Controler.GetModulesDatabaseInstance())
  1381             self.Controler.GetModulesDatabaseInstance())
  1382         
  1382 
  1383         if dialog.ShowModal() == wx.ID_OK:
  1383         if dialog.ShowModal() == wx.ID_OK:
  1384             module_library = self.Controler.GetModulesLibraryInstance()
  1384             module_library = self.Controler.GetModulesLibraryInstance()
  1385             module_library.ImportModuleLibrary(dialog.GetValue())
  1385             module_library.ImportModuleLibrary(dialog.GetValue())
  1386             
  1386 
  1387         dialog.Destroy()
  1387         dialog.Destroy()
  1388         
  1388 
  1389         wx.CallAfter(self.ModuleLibrarySizer.RefreshView)
  1389         wx.CallAfter(self.ModuleLibrarySizer.RefreshView)
  1390         
  1390 
  1391         event.Skip()
  1391         event.Skip()
  1392 
  1392 
  1393     def OnResize(self, event):
  1393     def OnResize(self, event):
  1394         self.ModuleLibraryEditor.GetBestSize()
  1394         self.ModuleLibraryEditor.GetBestSize()
  1395         xstart, ystart = self.ModuleLibraryEditor.GetViewStart()
  1395         xstart, ystart = self.ModuleLibraryEditor.GetViewStart()
  1396         window_size = self.ModuleLibraryEditor.GetClientSize()
  1396         window_size = self.ModuleLibraryEditor.GetClientSize()
  1397         maxx, maxy = self.ModuleLibraryEditor.GetMinSize()
  1397         maxx, maxy = self.ModuleLibraryEditor.GetMinSize()
  1398         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
  1398         posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
  1399         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
  1399         posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
  1400         self.ModuleLibraryEditor.Scroll(posx, posy)
  1400         self.ModuleLibraryEditor.Scroll(posx, posy)
  1401         self.ModuleLibraryEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
  1401         self.ModuleLibraryEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
  1402                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
  1402                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
  1403         event.Skip()
  1403         event.Skip()
  1404