etherlab/ConfigEditor.py
changeset 2034 ae8fecf082a1
parent 2030 7147f20c23e3
child 2037 d54036f70390
--- a/etherlab/ConfigEditor.py	Thu Feb 16 18:40:13 2012 +0100
+++ b/etherlab/ConfigEditor.py	Wed Feb 22 01:39:22 2012 +0100
@@ -145,20 +145,16 @@
                 grid.SetCellTextColour(row, col, highlight_colours[1])
             self.ResizeRow(grid, row)
 
-[ID_SLAVEPANEL, ID_SLAVEPANELTYPELABEL,
- ID_SLAVEPANELTYPE, ID_SLAVEPANELTYPEBROWSE, 
- ID_SLAVEPANELALIASLABEL, ID_SLAVEPANELALIAS, 
- ID_SLAVEPANELPOSLABEL, ID_SLAVEPANELPOS, 
- ID_SLAVEPANELSLAVEINFOSSTATICBOX, ID_SLAVEPANELVENDORLABEL, 
- ID_SLAVEPANELVENDOR, ID_SLAVEPANELPRODUCTCODELABEL, 
- ID_SLAVEPANELPRODUCTCODE, ID_SLAVEPANELREVISIONNUMBERLABEL, 
- ID_SLAVEPANELREVISIONNUMBER, ID_SLAVEPANELPHYSICSLABEL, 
- ID_SLAVEPANELPHYSICS, ID_SLAVEPANELSYNCMANAGERSLABEL, 
- ID_SLAVEPANELSYNCMANAGERSGRID, ID_SLAVEPANELVARIABLESLABEL, 
- ID_SLAVEPANELVARIABLESGRID, 
-] = [wx.NewId() for _init_ctrls in range(21)]
-
-class SlavePanel(wx.Panel):
+[ID_SLAVEINFOSPANEL, ID_SLAVEINFOSPANELVENDORLABEL, 
+ ID_SLAVEINFOSPANELVENDOR, ID_SLAVEINFOSPANELPRODUCTCODELABEL, 
+ ID_SLAVEINFOSPANELPRODUCTCODE, ID_SLAVEINFOSPANELREVISIONNUMBERLABEL, 
+ ID_SLAVEINFOSPANELREVISIONNUMBER, ID_SLAVEINFOSPANELPHYSICSLABEL, 
+ ID_SLAVEINFOSPANELPHYSICS, ID_SLAVEINFOSPANELSYNCMANAGERSLABEL, 
+ ID_SLAVEINFOSPANELSYNCMANAGERSGRID, ID_SLAVEINFOSPANELVARIABLESLABEL, 
+ ID_SLAVEINFOSPANELVARIABLESGRID, 
+] = [wx.NewId() for _init_ctrls in range(13)]
+
+class SlaveInfosPanel(wx.Panel):
     
     if wx.VERSION < (2, 6, 0):
         def Bind(self, event, function, id = None):
@@ -168,43 +164,14 @@
                 event(self, function)
     
     def _init_coll_MainSizer_Items(self, parent):
-        parent.AddSizer(self.PositionSizer, 0, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-        parent.AddSizer(self.SlaveInfosBoxSizer, 0, border=5, flag=wx.GROW|wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT)
-    
+        parent.AddSizer(self.SlaveInfosDetailsSizer, 0, border=5, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW)
+        parent.AddWindow(self.SyncManagersLabel, 0, border=5, flag=wx.LEFT|wx.RIGHT|wx.GROW)
+        parent.AddWindow(self.SyncManagersGrid, 0, border=5, flag=wx.LEFT|wx.RIGHT|wx.GROW)
+        parent.AddWindow(self.VariablesLabel, 0, border=5, flag=wx.LEFT|wx.RIGHT|wx.GROW)
+        parent.AddWindow(self.VariablesGrid, 0, border=5, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.GROW)
+        
     def _init_coll_MainSizer_Growables(self, parent):
         parent.AddGrowableCol(0)
-        parent.AddGrowableRow(1)
-    
-    def _init_coll_PositionSizer_Items(self, parent):
-        parent.AddWindow(self.TypeLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
-        parent.AddSizer(self.TypeSizer, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.AliasLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
-        parent.AddWindow(self.Alias, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.PosLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
-        parent.AddWindow(self.Pos, 0, border=0, flag=wx.GROW)
-    
-    def _init_coll_PositionSizer_Growables(self, parent):
-        parent.AddGrowableCol(1)
-        parent.AddGrowableCol(3)
-        parent.AddGrowableCol(5)
-        parent.AddGrowableRow(0)
-    
-    def _init_coll_TypeSizer_Items(self, parent):
-        parent.AddWindow(self.Type, 1, border=0, flag=0)
-        parent.AddWindow(self.TypeBrowse, 0, border=0, flag=0)
-    
-    def _init_coll_SlaveInfosBoxSizer_Items(self, parent):
-        parent.AddSizer(self.SlaveInfosSizer, 1, border=5, flag=wx.GROW|wx.ALL)
-    
-    def _init_coll_SlaveInfosSizer_Items(self, parent):
-        parent.AddSizer(self.SlaveInfosDetailsSizer, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.SyncManagersLabel, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.SyncManagersGrid, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.VariablesLabel, 0, border=0, flag=wx.GROW)
-        parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
-        
-    def _init_coll_SlaveInfosSizer_Growables(self, parent):
-        parent.AddGrowableCol(0)
         parent.AddGrowableRow(2, 1)
         parent.AddGrowableRow(4, 2)
         
@@ -223,110 +190,65 @@
         parent.AddGrowableCol(3)
     
     def _init_sizers(self):
-        self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
-        self.PositionSizer = wx.FlexGridSizer(cols=6, hgap=5, rows=1, vgap=0)
-        self.TypeSizer = wx.BoxSizer(wx.HORIZONTAL)
-        self.SlaveInfosBoxSizer = wx.StaticBoxSizer(self.SlaveInfosStaticBox, wx.VERTICAL)
-        self.SlaveInfosSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=5, vgap=5)
+        self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=5, vgap=5)
         self.SlaveInfosDetailsSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=2, vgap=5)
         
         self._init_coll_MainSizer_Growables(self.MainSizer)
         self._init_coll_MainSizer_Items(self.MainSizer)
-        self._init_coll_PositionSizer_Growables(self.PositionSizer)
-        self._init_coll_PositionSizer_Items(self.PositionSizer)
-        self._init_coll_TypeSizer_Items(self.TypeSizer)
-        self._init_coll_SlaveInfosBoxSizer_Items(self.SlaveInfosBoxSizer)
-        self._init_coll_SlaveInfosSizer_Growables(self.SlaveInfosSizer)
-        self._init_coll_SlaveInfosSizer_Items(self.SlaveInfosSizer)
         self._init_coll_SlaveInfosDetailsSizer_Growables(self.SlaveInfosDetailsSizer)
         self._init_coll_SlaveInfosDetailsSizer_Items(self.SlaveInfosDetailsSizer)
         
         self.SetSizer(self.MainSizer)
-    
+
     def _init_ctrls(self, prnt):
-        wx.Panel.__init__(self, id=ID_SLAVEPANEL, name='SlavePanel', parent=prnt,
+        wx.Panel.__init__(self, id=ID_SLAVEINFOSPANEL, name='SlavePanel', parent=prnt,
               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
         
-        self.TypeLabel = wx.StaticText(id=ID_SLAVEPANELTYPELABEL,
-              label=_('Type:'), name='TypeLabel', parent=self,
-              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
-        
-        self.Type = wx.TextCtrl(id=ID_SLAVEPANELTYPE, value='',
-              name='Type', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(0, 24), style=wx.TE_READONLY)
-        
-        self.TypeBrowse = wx.Button(id=ID_SLAVEPANELTYPEBROWSE, label='...',
-              name='TypeBrowse', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(30, 24), style=0)
-        self.Bind(wx.EVT_BUTTON, self.OnTypeBrowseClick, id=ID_SLAVEPANELTYPEBROWSE)
-        
-        self.AliasLabel = wx.StaticText(id=ID_SLAVEPANELALIASLABEL,
-              label=_('Alias:'), name='AliasLabel', parent=self,
-              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
-        
-        self.Alias = wx.SpinCtrl(id=ID_SLAVEPANELALIAS,
-              name='Alias', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff)
-        self.Bind(wx.EVT_SPINCTRL, self.OnAliasChanged, id=ID_SLAVEPANELALIAS)
-        
-        self.PosLabel = wx.StaticText(id=ID_SLAVEPANELPOSLABEL,
-              label=_('Position:'), name='PositionLabel', parent=self,
-              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
-        
-        self.Pos = wx.SpinCtrl(id=ID_SLAVEPANELPOS,
-              name='Pos', parent=self, pos=wx.Point(0, 0),
-              size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff)
-        self.Bind(wx.EVT_SPINCTRL, self.OnPositionChanged, id=ID_SLAVEPANELPOS)
-        
-        self.SlaveInfosStaticBox = wx.StaticBox(id=ID_SLAVEPANELSLAVEINFOSSTATICBOX,
-              label=_('Slave infos:'), name='SlaveInfosStaticBox', parent=self,
-              pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0)
-        
-        self.VendorLabel = wx.StaticText(id=ID_SLAVEPANELVENDORLABEL,
+        self.VendorLabel = wx.StaticText(id=ID_SLAVEINFOSPANELVENDORLABEL,
               label=_('Vendor:'), name='VendorLabel', parent=self,
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
         
-        self.Vendor = wx.TextCtrl(id=ID_SLAVEPANELVENDOR, value='',
+        self.Vendor = wx.TextCtrl(id=ID_SLAVEINFOSPANELVENDOR, value='',
               name='Vendor', parent=self, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=wx.TE_READONLY)
         
-        self.ProductCodeLabel = wx.StaticText(id=ID_SLAVEPANELPRODUCTCODELABEL,
+        self.ProductCodeLabel = wx.StaticText(id=ID_SLAVEINFOSPANELPRODUCTCODELABEL,
               label=_('Product code:'), name='ProductCodeLabel', parent=self,
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
         
-        self.ProductCode = wx.TextCtrl(id=ID_SLAVEPANELPRODUCTCODE, value='',
+        self.ProductCode = wx.TextCtrl(id=ID_SLAVEINFOSPANELPRODUCTCODE, value='',
               name='ProductCode', parent=self, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=wx.TE_READONLY)
         
-        self.RevisionNumberLabel = wx.StaticText(id=ID_SLAVEPANELREVISIONNUMBERLABEL,
+        self.RevisionNumberLabel = wx.StaticText(id=ID_SLAVEINFOSPANELREVISIONNUMBERLABEL,
               label=_('Revision number:'), name='RevisionNumberLabel', parent=self,
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
         
-        self.RevisionNumber = wx.TextCtrl(id=ID_SLAVEPANELREVISIONNUMBER, value='',
+        self.RevisionNumber = wx.TextCtrl(id=ID_SLAVEINFOSPANELREVISIONNUMBER, value='',
               name='RevisionNumber', parent=self, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=wx.TE_READONLY)
         
-        self.PhysicsLabel = wx.StaticText(id=ID_SLAVEPANELPHYSICSLABEL,
+        self.PhysicsLabel = wx.StaticText(id=ID_SLAVEINFOSPANELPHYSICSLABEL,
               label=_('Physics:'), name='PhysicsLabel', parent=self,
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
         
-        self.Physics = wx.TextCtrl(id=ID_SLAVEPANELPHYSICS, value='',
+        self.Physics = wx.TextCtrl(id=ID_SLAVEINFOSPANELPHYSICS, value='',
               name='Physics', parent=self, pos=wx.Point(0, 0),
               size=wx.Size(0, 24), style=wx.TE_READONLY)
         
-        self.SyncManagersLabel =  wx.StaticText(id=ID_SLAVEPANELSYNCMANAGERSLABEL,
+        self.SyncManagersLabel =  wx.StaticText(id=ID_SLAVEINFOSPANELSYNCMANAGERSLABEL,
               label=_('Sync managers:'), name='SyncManagersLabel', parent=self,
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
         
-        self.SyncManagersGrid = CustomGrid(id=ID_SLAVEPANELSYNCMANAGERSGRID,
+        self.SyncManagersGrid = CustomGrid(id=ID_SLAVEINFOSPANELSYNCMANAGERSGRID,
               name='SyncManagersGrid', parent=self, pos=wx.Point(0, 0), 
               size=wx.Size(0, 0), style=wx.VSCROLL)
         
-        self.VariablesLabel =  wx.StaticText(id=ID_SLAVEPANELVARIABLESLABEL,
+        self.VariablesLabel =  wx.StaticText(id=ID_SLAVEINFOSPANELVARIABLESLABEL,
               label=_('Variable entries:'), name='VariablesLabel', parent=self,
               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
         
-        self.VariablesGrid = CustomGrid(id=ID_SLAVEPANELVARIABLESGRID,
+        self.VariablesGrid = CustomGrid(id=ID_SLAVEINFOSPANELVARIABLESGRID,
               name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
               size=wx.Size(0, 0), style=wx.VSCROLL)
         if wx.VERSION >= (2, 5, 0):
@@ -335,13 +257,11 @@
             wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
         
         self._init_sizers()
-    
-    def __init__(self, parent, controler, window, slave):
+        
+    def __init__(self, parent, controler):
         self._init_ctrls(parent)
         
         self.Controler = controler
-        self.ParentWindow = window
-        self.Slave = slave
         
         self.SyncManagersTable = SyncManagersTable(self, [], GetSyncManagersTableColnames())
         self.SyncManagersGrid.SetTable(self.SyncManagersTable)
@@ -369,27 +289,9 @@
             self.VariablesGrid.SetColAttr(col, attr)
             self.VariablesGrid.SetColMinimalWidth(col, self.VariablesGridColSizes[col])
             self.VariablesGrid.AutoSizeColumn(col, False)
-        
-        self.RefreshView()
-    
-    def GetSlaveTitle(self):
-        type_infos = self.Controler.GetSlaveType(self.Slave)
-        return "%s (%d:%d)" % (type_infos["device_type"], self.Slave[0], self.Slave[1])
-    
-    def GetSlave(self):
-        return self.Slave
-    
-    def SetSlave(self, slave):
-        if self.Slave != slave:
-            self.Slave = slave
-            self.RefreshView()
-
-    def RefreshView(self):
-        self.Alias.SetValue(self.Slave[0])
-        self.Pos.SetValue(self.Slave[1])
-        slave_infos = self.Controler.GetSlaveInfos(self.Slave)
+    
+    def SetSlaveInfos(self, slave_infos):
         if slave_infos is not None:
-            self.Type.SetValue(slave_infos["device_type"])
             self.Vendor.SetValue(slave_infos["vendor"])
             self.ProductCode.SetValue(slave_infos["product_code"])
             self.RevisionNumber.SetValue(slave_infos["revision_number"])
@@ -399,49 +301,14 @@
             self.VariablesTable.SetData(slave_infos["entries"])
             self.VariablesTable.ResetView(self.VariablesGrid)
         else:
-            type_infos = self.Controler.GetSlaveType(self.Slave)
-            self.Type.SetValue(type_infos["device_type"])
-        
-    def OnAliasChanged(self, event):
-        alias = self.Alias.GetValue()
-        if alias != self.Slave[0]:
-            result = self.Controler.SetSlavePos(self.Slave[:2], alias = alias)
-            if result is not None:
-                message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
-                message.ShowModal()
-                message.Destroy()
-            else:
-                wx.CallAfter(self.ParentWindow.RefreshView, (alias, self.Slave[1]))
-                wx.CallAfter(self.ParentWindow.RefreshParentWindow)
-        event.Skip()
-        
-    def OnPositionChanged(self, event):
-        position = self.Pos.GetValue()
-        if position != self.Slave[1]:
-            result = self.Controler.SetSlavePos(self.Slave, position = position)
-            if result is not None:
-                message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
-                message.ShowModal()
-                message.Destroy()
-            else:
-                wx.CallAfter(self.ParentWindow.RefreshView, (self.Slave[0], position))
-                wx.CallAfter(self.ParentWindow.RefreshParentWindow)
-        event.Skip()
-
-    def OnTypeBrowseClick(self, event):
-        dialog = SlaveTypeChoiceDialog(self, self.Controler, self.Controler.GetSlaveType(self.Slave))
-        if dialog.ShowModal() == wx.ID_OK:
-            result = self.Controler.SetSlaveType(self.Slave, dialog.GetType())
-            if result is not None:
-                message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
-                message.ShowModal()
-                message.Destroy()
-            else:
-                wx.CallAfter(self.RefreshView)
-                wx.CallAfter(self.ParentWindow.RefreshSlaveNodesTitles)
-                wx.CallAfter(self.ParentWindow.RefreshParentWindow)
-        dialog.Destroy()
-        event.Skip()
+            self.Vendor.SetValue("")
+            self.ProductCode.SetValue("")
+            self.RevisionNumber.SetValue("")
+            self.Physics.SetValue("")
+            self.SyncManagersTable.SetData([])
+            self.SyncManagersTable.ResetView(self.SyncManagersGrid)
+            self.VariablesTable.SetData([])
+            self.VariablesTable.ResetView(self.VariablesGrid)
 
     def OnVariablesGridCellLeftClick(self, event):
         row = event.GetRow()
@@ -468,9 +335,184 @@
         
         event.Skip()
 
-[ID_CONFIGEDITOR, ID_CONFIGEDITORADDSLAVEBUTTON,
- ID_CONFIGEDITORDELETESLAVEBUTTON, ID_CONFIGEDITORSLAVENODES,
-] = [wx.NewId() for _init_ctrls in range(4)]
+[ID_SLAVEPANEL, ID_SLAVEPANELTYPELABEL,
+ ID_SLAVEPANELTYPE, ID_SLAVEPANELTYPEBROWSE, 
+ ID_SLAVEPANELALIASLABEL, ID_SLAVEPANELALIAS, 
+ ID_SLAVEPANELPOSLABEL, ID_SLAVEPANELPOS, 
+ ID_SLAVEPANELSLAVEINFOSSTATICBOX, 
+] = [wx.NewId() for _init_ctrls in range(9)]
+
+class SlavePanel(wx.Panel):
+    
+    if wx.VERSION < (2, 6, 0):
+        def Bind(self, event, function, id = None):
+            if id is not None:
+                event(self, id, function)
+            else:
+                event(self, function)
+    
+    def _init_coll_MainSizer_Items(self, parent):
+        parent.AddSizer(self.PositionSizer, 0, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+        parent.AddSizer(self.SlaveInfosBoxSizer, 0, border=5, flag=wx.GROW|wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT)
+    
+    def _init_coll_MainSizer_Growables(self, parent):
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(1)
+    
+    def _init_coll_PositionSizer_Items(self, parent):
+        parent.AddWindow(self.TypeLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
+        parent.AddSizer(self.TypeSizer, 0, border=0, flag=wx.GROW)
+        parent.AddWindow(self.AliasLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
+        parent.AddWindow(self.Alias, 0, border=0, flag=wx.GROW)
+        parent.AddWindow(self.PosLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
+        parent.AddWindow(self.Pos, 0, border=0, flag=wx.GROW)
+    
+    def _init_coll_PositionSizer_Growables(self, parent):
+        parent.AddGrowableCol(1)
+        parent.AddGrowableCol(3)
+        parent.AddGrowableCol(5)
+        parent.AddGrowableRow(0)
+    
+    def _init_coll_TypeSizer_Items(self, parent):
+        parent.AddWindow(self.Type, 1, border=0, flag=0)
+        parent.AddWindow(self.TypeBrowse, 0, border=0, flag=0)
+    
+    def _init_coll_SlaveInfosBoxSizer_Items(self, parent):
+        parent.AddWindow(self.SlaveInfosPanel, 1, border=0, flag=wx.GROW)
+    
+    def _init_sizers(self):
+        self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
+        self.PositionSizer = wx.FlexGridSizer(cols=6, hgap=5, rows=1, vgap=0)
+        self.TypeSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.SlaveInfosBoxSizer = wx.StaticBoxSizer(self.SlaveInfosStaticBox, wx.VERTICAL)
+        
+        self._init_coll_MainSizer_Growables(self.MainSizer)
+        self._init_coll_MainSizer_Items(self.MainSizer)
+        self._init_coll_PositionSizer_Growables(self.PositionSizer)
+        self._init_coll_PositionSizer_Items(self.PositionSizer)
+        self._init_coll_TypeSizer_Items(self.TypeSizer)
+        self._init_coll_SlaveInfosBoxSizer_Items(self.SlaveInfosBoxSizer)
+        
+        self.SetSizer(self.MainSizer)
+    
+    def _init_ctrls(self, prnt):
+        wx.Panel.__init__(self, id=ID_SLAVEPANEL, name='SlavePanel', parent=prnt,
+              size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+        
+        self.TypeLabel = wx.StaticText(id=ID_SLAVEPANELTYPELABEL,
+              label=_('Type:'), name='TypeLabel', parent=self,
+              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+        
+        self.Type = wx.TextCtrl(id=ID_SLAVEPANELTYPE, value='',
+              name='Type', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=wx.TE_READONLY)
+        
+        self.TypeBrowse = wx.Button(id=ID_SLAVEPANELTYPEBROWSE, label='...',
+              name='TypeBrowse', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(30, 24), style=0)
+        self.Bind(wx.EVT_BUTTON, self.OnTypeBrowseClick, id=ID_SLAVEPANELTYPEBROWSE)
+        
+        self.AliasLabel = wx.StaticText(id=ID_SLAVEPANELALIASLABEL,
+              label=_('Alias:'), name='AliasLabel', parent=self,
+              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+        
+        self.Alias = wx.SpinCtrl(id=ID_SLAVEPANELALIAS,
+              name='Alias', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff)
+        self.Bind(wx.EVT_SPINCTRL, self.OnAliasChanged, id=ID_SLAVEPANELALIAS)
+        
+        self.PosLabel = wx.StaticText(id=ID_SLAVEPANELPOSLABEL,
+              label=_('Position:'), name='PositionLabel', parent=self,
+              pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+        
+        self.Pos = wx.SpinCtrl(id=ID_SLAVEPANELPOS,
+              name='Pos', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff)
+        self.Bind(wx.EVT_SPINCTRL, self.OnPositionChanged, id=ID_SLAVEPANELPOS)
+        
+        self.SlaveInfosStaticBox = wx.StaticBox(id=ID_SLAVEPANELSLAVEINFOSSTATICBOX,
+              label=_('Slave infos:'), name='SlaveInfosStaticBox', parent=self,
+              pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0)
+        
+        self.SlaveInfosPanel = SlaveInfosPanel(self, self.Controler)
+        
+        self._init_sizers()
+    
+    def __init__(self, parent, controler, window, slave):
+        self.Controler = controler
+        self.ParentWindow = window
+        self.Slave = slave
+        
+        self._init_ctrls(parent)
+        
+        self.RefreshView()
+    
+    def GetSlaveTitle(self):
+        type_infos = self.Controler.GetSlaveType(self.Slave)
+        return "%s (%d:%d)" % (type_infos["device_type"], self.Slave[0], self.Slave[1])
+    
+    def GetSlave(self):
+        return self.Slave
+    
+    def SetSlave(self, slave):
+        if self.Slave != slave:
+            self.Slave = slave
+            self.RefreshView()
+
+    def RefreshView(self):
+        self.Alias.SetValue(self.Slave[0])
+        self.Pos.SetValue(self.Slave[1])
+        slave_infos = self.Controler.GetSlaveInfos(self.Slave)
+        if slave_infos is not None:
+            self.Type.SetValue(slave_infos["device_type"])
+        else:
+            type_infos = self.Controler.GetSlaveType(self.Slave)
+            self.Type.SetValue(type_infos["device_type"])
+        self.SlaveInfosPanel.SetSlaveInfos(slave_infos)
+        
+    def OnAliasChanged(self, event):
+        alias = self.Alias.GetValue()
+        if alias != self.Slave[0]:
+            result = self.Controler.SetSlavePos(self.Slave[:2], alias = alias)
+            if result is not None:
+                message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+            else:
+                wx.CallAfter(self.ParentWindow.RefreshView, (alias, self.Slave[1]))
+                wx.CallAfter(self.ParentWindow.RefreshParentWindow)
+        event.Skip()
+        
+    def OnPositionChanged(self, event):
+        position = self.Pos.GetValue()
+        if position != self.Slave[1]:
+            result = self.Controler.SetSlavePos(self.Slave, position = position)
+            if result is not None:
+                message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+            else:
+                wx.CallAfter(self.ParentWindow.RefreshView, (self.Slave[0], position))
+                wx.CallAfter(self.ParentWindow.RefreshParentWindow)
+        event.Skip()
+
+    def OnTypeBrowseClick(self, event):
+        dialog = SlaveTypeChoiceDialog(self, self.Controler, self.Controler.GetSlaveType(self.Slave))
+        if dialog.ShowModal() == wx.ID_OK:
+            result = self.Controler.SetSlaveType(self.Slave, dialog.GetType())
+            if result is not None:
+                message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
+                message.ShowModal()
+                message.Destroy()
+            else:
+                wx.CallAfter(self.RefreshView)
+                wx.CallAfter(self.ParentWindow.RefreshSlaveNodesTitles)
+                wx.CallAfter(self.ParentWindow.RefreshParentWindow)
+        dialog.Destroy()
+        event.Skip()
+
+[ID_CONFIGEDITOR, ID_CONFIGEDITORSLAVENODES,
+] = [wx.NewId() for _init_ctrls in range(2)]
 
 [ID_CONFIGEDITORPLUGINMENUADDSLAVE, ID_CONFIGEDITORPLUGINMENUDELETESLAVE,
 ] = [wx.NewId() for _init_coll_PluginMenu_Items in range(2)]
@@ -586,4 +628,33 @@
             if self.Controler.RemoveSlave(panel.GetSlave()[:2]):
                 self.RefreshParentWindow()
                 wx.CallAfter(self.RefreshView)
-            
\ No newline at end of file
+
+
+[ID_DS402NODEEDITOR,
+] = [wx.NewId() for _init_ctrls in range(1)]
+
+class DS402NodeEditor(EditorPanel):
+    
+    ID = ID_DS402NODEEDITOR
+    
+    def _init_Editor(self, prnt):
+        self.Editor = SlaveInfosPanel(prnt, self.Controler)
+        
+    def __init__(self, parent, controler, window):
+        EditorPanel.__init__(self, parent, "", window, controler)
+        
+        img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
+        self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
+    
+    def __del__(self):
+        self.Controler.OnCloseEditor(self)
+    
+    def GetTitle(self):
+        return self.Controler.PlugFullName()
+    
+    def GetBufferState(self):
+        return False, False
+        
+    def RefreshView(self):
+        self.Editor.SetSlaveInfos(self.Controler.GetSlaveInfos())
+        
\ No newline at end of file