etherlab/ConfigEditor.py
changeset 2022 c2295d311402
child 2023 f9f884cf3033
equal deleted inserted replaced
-1:000000000000 2022:c2295d311402
       
     1 import wx
       
     2 
       
     3 from controls import CustomGrid, CustomTable, EditorPanel
       
     4 
       
     5 [ETHERCAT_VENDOR, ETHERCAT_GROUP, ETHERCAT_DEVICE] = range(3)
       
     6 
       
     7 def AppendMenu(parent, help, id, kind, text):
       
     8     if wx.VERSION >= (2, 6, 0):
       
     9         parent.Append(help=help, id=id, kind=kind, text=text)
       
    10     else:
       
    11         parent.Append(helpString=help, id=id, kind=kind, item=text)
       
    12 
       
    13 [ID_SLAVETYPECHOICEDIALOG, ID_SLAVETYPECHOICEDIALOGSTATICTEXT1,
       
    14  ID_SLAVETYPECHOICEDIALOGSLAVETYPESLIBRARY
       
    15 ] = [wx.NewId() for _init_ctrls in range(3)]
       
    16 
       
    17 class SlaveTypeChoiceDialog(wx.Dialog):
       
    18     
       
    19     if wx.VERSION < (2, 6, 0):
       
    20         def Bind(self, event, function, id = None):
       
    21             if id is not None:
       
    22                 event(self, id, function)
       
    23             else:
       
    24                 event(self, function)
       
    25     
       
    26     def _init_coll_flexGridSizer1_Items(self, parent):
       
    27         parent.AddWindow(self.staticText1, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
       
    28         parent.AddWindow(self.SlaveTypesLibrary, 0, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT)
       
    29         parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
       
    30     
       
    31     def _init_coll_flexGridSizer1_Growables(self, parent):
       
    32         parent.AddGrowableCol(0)
       
    33         parent.AddGrowableRow(1)
       
    34     
       
    35     def _init_sizers(self):
       
    36         self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
       
    37         
       
    38         self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
       
    39         self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
       
    40         
       
    41         self.SetSizer(self.flexGridSizer1)
       
    42 
       
    43     def _init_ctrls(self, prnt):
       
    44         wx.Dialog.__init__(self, id=ID_SLAVETYPECHOICEDIALOG,
       
    45               name='SlaveTypeChoiceDialog', parent=prnt,
       
    46               size=wx.Size(600, 400), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,
       
    47               title=_('Browse slave types library'))
       
    48         self.SetClientSize(wx.Size(600, 400))
       
    49 
       
    50         self.staticText1 = wx.StaticText(id=ID_SLAVETYPECHOICEDIALOGSTATICTEXT1,
       
    51               label=_('Choose a slave type:'), name='staticText1', parent=self,
       
    52               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
    53         
       
    54         self.SlaveTypesLibrary = wx.TreeCtrl(id=ID_SLAVETYPECHOICEDIALOGSLAVETYPESLIBRARY,
       
    55               name='TypeTree', parent=self, pos=wx.Point(0, 0),
       
    56               size=wx.Size(0, 0), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT)
       
    57         
       
    58         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
       
    59         if wx.VERSION >= (2, 5, 0):
       
    60             self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
       
    61         else:
       
    62             self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
       
    63         
       
    64         self._init_sizers()
       
    65 
       
    66     def __init__(self, parent, controler, default=None):
       
    67         self._init_ctrls(parent)
       
    68         
       
    69         slaves_types = controler.GetSlaveTypesLibrary()
       
    70         
       
    71         root = self.SlaveTypesLibrary.AddRoot("")
       
    72         self.GenerateSlaveTypesLibraryTreeBranch(root, slaves_types, default)
       
    73 
       
    74     def GenerateSlaveTypesLibraryTreeBranch(self, root, children, default):
       
    75         for infos in children:
       
    76             item = self.SlaveTypesLibrary.AppendItem(root, infos["name"])
       
    77             if infos["type"] == ETHERCAT_DEVICE:
       
    78                 self.SlaveTypesLibrary.SetPyData(item, infos["infos"])
       
    79                 if infos["infos"] == default:
       
    80                     self.SlaveTypesLibrary.SelectItem(item)
       
    81                     self.SlaveTypesLibrary.EnsureVisible(item)
       
    82             else:
       
    83                 self.GenerateSlaveTypesLibraryTreeBranch(item, infos["children"], default)
       
    84 
       
    85     def GetType(self):
       
    86         selected = self.SlaveTypesLibrary.GetSelection()
       
    87         return self.SlaveTypesLibrary.GetPyData(selected)
       
    88 
       
    89     def OnOK(self, event):
       
    90         selected = self.SlaveTypesLibrary.GetSelection()
       
    91         if not selected.IsOk() or self.SlaveTypesLibrary.GetPyData(selected) is None:
       
    92             message = wx.MessageDialog(self, _("No valid slave type selected!"), _("Error"), wx.OK|wx.ICON_ERROR)
       
    93             message.ShowModal()
       
    94             message.Destroy()
       
    95         else:
       
    96             self.EndModal(wx.ID_OK)
       
    97 
       
    98 
       
    99 def GetPDOsTableColnames():
       
   100     _ = lambda x : x
       
   101     return ["#", _("Index"), _("Name"), _("Type")]
       
   102 
       
   103 def GetVariablesTableColnames():
       
   104     _ = lambda x : x
       
   105     return ["#", _("Index"), _("SubIndex"), _("Name"), _("Type"), _("PDO")]
       
   106 
       
   107 class PDOsTable(CustomTable):
       
   108     
       
   109     def GetValue(self, row, col):
       
   110         if row < self.GetNumberRows():
       
   111             if col == 0:
       
   112                 return row + 1
       
   113             colname = self.GetColLabelValue(col, False)
       
   114             value = self.data[row].get(colname, "")
       
   115             if colname == "Type":
       
   116                 value = _(value)
       
   117             return value
       
   118 
       
   119 class VariablesTable(CustomTable):
       
   120     
       
   121     def GetValue(self, row, col):
       
   122         if row < self.GetNumberRows():
       
   123             if col == 0:
       
   124                 return row + 1
       
   125             return self.data[row].get(self.GetColLabelValue(col, False), "")
       
   126 
       
   127 [ID_SLAVEPANEL, ID_SLAVEPANELTYPELABEL,
       
   128  ID_SLAVEPANELTYPE, ID_SLAVEPANELTYPEBROWSE, 
       
   129  ID_SLAVEPANELALIASLABEL, ID_SLAVEPANELALIAS, 
       
   130  ID_SLAVEPANELPOSLABEL, ID_SLAVEPANELPOS, 
       
   131  ID_SLAVEPANELSLAVEINFOSSTATICBOX, ID_SLAVEPANELVENDORLABEL, 
       
   132  ID_SLAVEPANELVENDOR, ID_SLAVEPANELPRODUCTCODELABEL, 
       
   133  ID_SLAVEPANELPRODUCTCODE, ID_SLAVEPANELREVISIONNUMBERLABEL, 
       
   134  ID_SLAVEPANELREVISIONNUMBER, ID_SLAVEPANELPHYSICSLABEL, 
       
   135  ID_SLAVEPANELPHYSICS, ID_SLAVEPANELPDOSLABEL, 
       
   136  ID_SLAVEPANELPDOSGRID, ID_SLAVEPANELVARIABLESLABEL, 
       
   137  ID_SLAVEPANELVARIABLESGRID, 
       
   138 ] = [wx.NewId() for _init_ctrls in range(21)]
       
   139 
       
   140 class SlavePanel(wx.Panel):
       
   141     
       
   142     if wx.VERSION < (2, 6, 0):
       
   143         def Bind(self, event, function, id = None):
       
   144             if id is not None:
       
   145                 event(self, id, function)
       
   146             else:
       
   147                 event(self, function)
       
   148     
       
   149     def _init_coll_MainSizer_Items(self, parent):
       
   150         parent.AddSizer(self.PositionSizer, 0, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
       
   151         parent.AddSizer(self.SlaveInfosBoxSizer, 0, border=5, flag=wx.GROW|wx.ALIGN_RIGHT|wx.LEFT|wx.RIGHT)
       
   152     
       
   153     def _init_coll_MainSizer_Growables(self, parent):
       
   154         parent.AddGrowableCol(0)
       
   155         parent.AddGrowableRow(1)
       
   156     
       
   157     def _init_coll_PositionSizer_Items(self, parent):
       
   158         parent.AddWindow(self.TypeLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
       
   159         parent.AddSizer(self.TypeSizer, 0, border=0, flag=wx.GROW)
       
   160         parent.AddWindow(self.AliasLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
       
   161         parent.AddWindow(self.Alias, 0, border=0, flag=wx.GROW)
       
   162         parent.AddWindow(self.PosLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL)
       
   163         parent.AddWindow(self.Pos, 0, border=0, flag=wx.GROW)
       
   164     
       
   165     def _init_coll_PositionSizer_Growables(self, parent):
       
   166         parent.AddGrowableCol(1)
       
   167         parent.AddGrowableCol(3)
       
   168         parent.AddGrowableCol(5)
       
   169         parent.AddGrowableRow(0)
       
   170     
       
   171     def _init_coll_TypeSizer_Items(self, parent):
       
   172         parent.AddWindow(self.Type, 1, border=0, flag=0)
       
   173         parent.AddWindow(self.TypeBrowse, 0, border=0, flag=0)
       
   174     
       
   175     def _init_coll_SlaveInfosBoxSizer_Items(self, parent):
       
   176         parent.AddSizer(self.SlaveInfosSizer, 1, border=5, flag=wx.GROW|wx.ALL)
       
   177     
       
   178     def _init_coll_SlaveInfosSizer_Items(self, parent):
       
   179         parent.AddSizer(self.SlaveInfosDetailsSizer, 0, border=0, flag=wx.GROW)
       
   180         parent.AddWindow(self.PDOsLabel, 0, border=0, flag=wx.GROW)
       
   181         parent.AddWindow(self.PDOsGrid, 0, border=0, flag=wx.GROW)
       
   182         parent.AddWindow(self.VariablesLabel, 0, border=0, flag=wx.GROW)
       
   183         parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
       
   184         
       
   185     def _init_coll_SlaveInfosSizer_Growables(self, parent):
       
   186         parent.AddGrowableCol(0)
       
   187         parent.AddGrowableRow(2)
       
   188         parent.AddGrowableRow(4)
       
   189     
       
   190     def _init_coll_SlaveInfosDetailsSizer_Items(self, parent):
       
   191         parent.AddWindow(self.VendorLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW)
       
   192         parent.AddWindow(self.Vendor, 0, border=0, flag=wx.GROW)
       
   193         parent.AddWindow(self.ProductCodeLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW)
       
   194         parent.AddWindow(self.ProductCode, 0, border=0, flag=wx.GROW)
       
   195         parent.AddWindow(self.RevisionNumberLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW)
       
   196         parent.AddWindow(self.RevisionNumber, 0, border=0, flag=wx.GROW)
       
   197         parent.AddWindow(self.PhysicsLabel, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.GROW)
       
   198         parent.AddWindow(self.Physics, 0, border=0, flag=wx.GROW)
       
   199         
       
   200     def _init_coll_SlaveInfosDetailsSizer_Growables(self, parent):
       
   201         parent.AddGrowableCol(1)
       
   202         parent.AddGrowableCol(3)
       
   203     
       
   204     def _init_sizers(self):
       
   205         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
       
   206         self.PositionSizer = wx.FlexGridSizer(cols=6, hgap=5, rows=1, vgap=0)
       
   207         self.TypeSizer = wx.BoxSizer(wx.HORIZONTAL)
       
   208         self.SlaveInfosBoxSizer = wx.StaticBoxSizer(self.SlaveInfosStaticBox, wx.VERTICAL)
       
   209         self.SlaveInfosSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=5, vgap=5)
       
   210         self.SlaveInfosDetailsSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=2, vgap=5)
       
   211         
       
   212         self._init_coll_MainSizer_Growables(self.MainSizer)
       
   213         self._init_coll_MainSizer_Items(self.MainSizer)
       
   214         self._init_coll_PositionSizer_Growables(self.PositionSizer)
       
   215         self._init_coll_PositionSizer_Items(self.PositionSizer)
       
   216         self._init_coll_TypeSizer_Items(self.TypeSizer)
       
   217         self._init_coll_SlaveInfosBoxSizer_Items(self.SlaveInfosBoxSizer)
       
   218         self._init_coll_SlaveInfosSizer_Growables(self.SlaveInfosSizer)
       
   219         self._init_coll_SlaveInfosSizer_Items(self.SlaveInfosSizer)
       
   220         self._init_coll_SlaveInfosDetailsSizer_Growables(self.SlaveInfosDetailsSizer)
       
   221         self._init_coll_SlaveInfosDetailsSizer_Items(self.SlaveInfosDetailsSizer)
       
   222         
       
   223         self.SetSizer(self.MainSizer)
       
   224     
       
   225     def _init_ctrls(self, prnt):
       
   226         wx.Panel.__init__(self, id=ID_SLAVEPANEL, name='SlavePanel', parent=prnt,
       
   227               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
   228         
       
   229         self.TypeLabel = wx.StaticText(id=ID_SLAVEPANELTYPELABEL,
       
   230               label=_('Type:'), name='TypeLabel', parent=self,
       
   231               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   232         
       
   233         self.Type = wx.TextCtrl(id=ID_SLAVEPANELTYPE, value='',
       
   234               name='Type', parent=self, pos=wx.Point(0, 0),
       
   235               size=wx.Size(0, 24), style=wx.TE_READONLY)
       
   236         
       
   237         self.TypeBrowse = wx.Button(id=ID_SLAVEPANELTYPEBROWSE, label='...',
       
   238               name='TypeBrowse', parent=self, pos=wx.Point(0, 0),
       
   239               size=wx.Size(30, 24), style=0)
       
   240         self.Bind(wx.EVT_BUTTON, self.OnTypeBrowseClick, id=ID_SLAVEPANELTYPEBROWSE)
       
   241         
       
   242         self.AliasLabel = wx.StaticText(id=ID_SLAVEPANELALIASLABEL,
       
   243               label=_('Alias:'), name='AliasLabel', parent=self,
       
   244               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   245         
       
   246         self.Alias = wx.SpinCtrl(id=ID_SLAVEPANELALIAS,
       
   247               name='Alias', parent=self, pos=wx.Point(0, 0),
       
   248               size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff)
       
   249         self.Bind(wx.EVT_SPINCTRL, self.OnAliasChanged, id=ID_SLAVEPANELALIAS)
       
   250         
       
   251         self.PosLabel = wx.StaticText(id=ID_SLAVEPANELPOSLABEL,
       
   252               label=_('Position:'), name='PositionLabel', parent=self,
       
   253               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   254         
       
   255         self.Pos = wx.SpinCtrl(id=ID_SLAVEPANELPOS,
       
   256               name='Pos', parent=self, pos=wx.Point(0, 0),
       
   257               size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0, max=0xffff)
       
   258         self.Bind(wx.EVT_SPINCTRL, self.OnPositionChanged, id=ID_SLAVEPANELPOS)
       
   259         
       
   260         self.SlaveInfosStaticBox = wx.StaticBox(id=ID_SLAVEPANELSLAVEINFOSSTATICBOX,
       
   261               label=_('Slave infos:'), name='SlaveInfosStaticBox', parent=self,
       
   262               pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0)
       
   263         
       
   264         self.VendorLabel = wx.StaticText(id=ID_SLAVEPANELVENDORLABEL,
       
   265               label=_('Vendor:'), name='VendorLabel', parent=self,
       
   266               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   267         
       
   268         self.Vendor = wx.TextCtrl(id=ID_SLAVEPANELVENDOR, value='',
       
   269               name='Vendor', parent=self, pos=wx.Point(0, 0),
       
   270               size=wx.Size(0, 24), style=wx.TE_READONLY)
       
   271         
       
   272         self.ProductCodeLabel = wx.StaticText(id=ID_SLAVEPANELPRODUCTCODELABEL,
       
   273               label=_('Product code:'), name='ProductCodeLabel', parent=self,
       
   274               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   275         
       
   276         self.ProductCode = wx.TextCtrl(id=ID_SLAVEPANELPRODUCTCODE, value='',
       
   277               name='ProductCode', parent=self, pos=wx.Point(0, 0),
       
   278               size=wx.Size(0, 24), style=wx.TE_READONLY)
       
   279         
       
   280         self.RevisionNumberLabel = wx.StaticText(id=ID_SLAVEPANELREVISIONNUMBERLABEL,
       
   281               label=_('Revision number:'), name='RevisionNumberLabel', parent=self,
       
   282               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   283         
       
   284         self.RevisionNumber = wx.TextCtrl(id=ID_SLAVEPANELREVISIONNUMBER, value='',
       
   285               name='RevisionNumber', parent=self, pos=wx.Point(0, 0),
       
   286               size=wx.Size(0, 24), style=wx.TE_READONLY)
       
   287         
       
   288         self.PhysicsLabel = wx.StaticText(id=ID_SLAVEPANELPHYSICSLABEL,
       
   289               label=_('Physics:'), name='PhysicsLabel', parent=self,
       
   290               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   291         
       
   292         self.Physics = wx.TextCtrl(id=ID_SLAVEPANELPHYSICS, value='',
       
   293               name='Physics', parent=self, pos=wx.Point(0, 0),
       
   294               size=wx.Size(0, 24), style=wx.TE_READONLY)
       
   295         
       
   296         self.PDOsLabel =  wx.StaticText(id=ID_SLAVEPANELPDOSLABEL,
       
   297               label=_('PDO entries:'), name='PDOsLabel', parent=self,
       
   298               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   299         
       
   300         self.PDOsGrid = CustomGrid(id=ID_SLAVEPANELPDOSGRID,
       
   301               name='PDOsGrid', parent=self, pos=wx.Point(0, 0), 
       
   302               size=wx.Size(0, 0), style=wx.VSCROLL)
       
   303         
       
   304         self.VariablesLabel =  wx.StaticText(id=ID_SLAVEPANELVARIABLESLABEL,
       
   305               label=_('Variable entries:'), name='VariablesLabel', parent=self,
       
   306               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
   307         
       
   308         self.VariablesGrid = CustomGrid(id=ID_SLAVEPANELPDOSGRID,
       
   309               name='PDOsGrid', parent=self, pos=wx.Point(0, 0), 
       
   310               size=wx.Size(0, 0), style=wx.VSCROLL)
       
   311         if wx.VERSION >= (2, 5, 0):
       
   312             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
       
   313         else:
       
   314             wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
       
   315         
       
   316         self._init_sizers()
       
   317     
       
   318     def __init__(self, parent, controler, window, slave):
       
   319         self._init_ctrls(parent)
       
   320         
       
   321         self.Controler = controler
       
   322         self.ParentWindow = window
       
   323         self.Slave = slave
       
   324         
       
   325         self.PDOsTable = PDOsTable(self, [], GetPDOsTableColnames())
       
   326         self.PDOsGrid.SetTable(self.PDOsTable)
       
   327         self.PDOsGridColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
       
   328         self.PDOsGridColSizes = [40, 100, 150, 150]
       
   329         self.PDOsGrid.SetRowLabelSize(0)
       
   330         for col in range(self.PDOsTable.GetNumberCols()):
       
   331             attr = wx.grid.GridCellAttr()
       
   332             attr.SetAlignment(self.PDOsGridColAlignements[col], wx.ALIGN_CENTRE)
       
   333             self.PDOsGrid.SetColAttr(col, attr)
       
   334             self.PDOsGrid.SetColMinimalWidth(col, self.PDOsGridColSizes[col])
       
   335             self.PDOsGrid.AutoSizeColumn(col, False)
       
   336         
       
   337         self.VariablesTable = VariablesTable(self, [], GetVariablesTableColnames())
       
   338         self.VariablesGrid.SetTable(self.VariablesTable)
       
   339         self.VariablesGridColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT]
       
   340         self.VariablesGridColSizes = [40, 100, 100, 150, 150, 100]
       
   341         self.VariablesGrid.SetRowLabelSize(0)
       
   342         for col in range(self.VariablesTable.GetNumberCols()):
       
   343             attr = wx.grid.GridCellAttr()
       
   344             attr.SetAlignment(self.VariablesGridColAlignements[col], wx.ALIGN_CENTRE)
       
   345             self.VariablesGrid.SetColAttr(col, attr)
       
   346             self.VariablesGrid.SetColMinimalWidth(col, self.VariablesGridColSizes[col])
       
   347             self.VariablesGrid.AutoSizeColumn(col, False)
       
   348         
       
   349         self.RefreshView()
       
   350     
       
   351     def GetSlaveTitle(self):
       
   352         type_infos = self.Controler.GetSlaveType(self.Slave)
       
   353         return "%s (%d:%d)" % (type_infos["device_type"], self.Slave[0], self.Slave[1])
       
   354     
       
   355     def GetSlave(self):
       
   356         return self.Slave
       
   357     
       
   358     def SetSlave(self, slave):
       
   359         if self.Slave != slave:
       
   360             self.Slave = slave
       
   361             self.RefreshView()
       
   362 
       
   363     def RefreshView(self):
       
   364         self.Alias.SetValue(self.Slave[0])
       
   365         self.Pos.SetValue(self.Slave[1])
       
   366         slave_infos = self.Controler.GetSlaveInfos(self.Slave)
       
   367         if slave_infos is not None:
       
   368             self.Type.SetValue(slave_infos["device_type"])
       
   369             self.Vendor.SetValue(slave_infos["vendor"])
       
   370             self.ProductCode.SetValue(slave_infos["product_code"])
       
   371             self.RevisionNumber.SetValue(slave_infos["revision_number"])
       
   372             self.Physics.SetValue(slave_infos["physics"])
       
   373             self.PDOsTable.SetData(slave_infos["pdos"])
       
   374             self.PDOsTable.ResetView(self.PDOsGrid)
       
   375             self.VariablesTable.SetData(slave_infos["variables"])
       
   376             self.VariablesTable.ResetView(self.VariablesGrid)
       
   377         else:
       
   378             type_infos = self.Controler.GetSlaveType(self.Slave)
       
   379             self.Type.SetValue(type_infos["device_type"])
       
   380         
       
   381     def OnAliasChanged(self, event):
       
   382         alias = self.Alias.GetValue()
       
   383         if alias != self.Slave[0]:
       
   384             result = self.Controler.SetSlavePos(self.Slave[:2], alias = alias)
       
   385             if result is not None:
       
   386                 message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
       
   387                 message.ShowModal()
       
   388                 message.Destroy()
       
   389             else:
       
   390                 wx.CallAfter(self.ParentWindow.RefreshView, (alias, self.Slave[1]))
       
   391                 wx.CallAfter(self.ParentWindow.RefreshParentWindow)
       
   392         event.Skip()
       
   393         
       
   394     def OnPositionChanged(self, event):
       
   395         position = self.Pos.GetValue()
       
   396         if position != self.Slave[1]:
       
   397             result = self.Controler.SetSlavePos(self.Slave, position = position)
       
   398             if result is not None:
       
   399                 message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
       
   400                 message.ShowModal()
       
   401                 message.Destroy()
       
   402             else:
       
   403                 wx.CallAfter(self.ParentWindow.RefreshView, (self.Slave[0], position))
       
   404                 wx.CallAfter(self.ParentWindow.RefreshParentWindow)
       
   405         event.Skip()
       
   406 
       
   407     def OnTypeBrowseClick(self, event):
       
   408         dialog = SlaveTypeChoiceDialog(self, self.Controler, self.Controler.GetSlaveType(self.Slave))
       
   409         if dialog.ShowModal() == wx.ID_OK:
       
   410             result = self.Controler.SetSlaveType(self.Slave, dialog.GetType())
       
   411             if result is not None:
       
   412                 message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
       
   413                 message.ShowModal()
       
   414                 message.Destroy()
       
   415             else:
       
   416                 wx.CallAfter(self.RefreshView)
       
   417                 wx.CallAfter(self.ParentWindow.RefreshSlaveNodesTitles)
       
   418                 wx.CallAfter(self.ParentWindow.RefreshParentWindow)
       
   419         dialog.Destroy()
       
   420         event.Skip()
       
   421 
       
   422     def OnVariablesGridCellLeftClick(self, event):
       
   423         if event.GetCol() == 0:
       
   424             row = event.GetRow()
       
   425             data_type = self.VariablesTable.GetValueByName(row, "Type")
       
   426             var_name = self.VariablesTable.GetValueByName(row, "Name")
       
   427             entry_index = self.Controler.ExtractHexDecValue(self.VariablesTable.GetValueByName(row, "Index"))
       
   428             entry_subindex = self.VariablesTable.GetValueByName(row, "SubIndex")
       
   429             pdo_index = self.VariablesTable.GetValueByName(row, "PDO")
       
   430             for pdo_row in xrange(self.PDOsTable.GetNumberRows()):
       
   431                 if self.PDOsTable.GetValueByName(row, "Index") == pdo_index:
       
   432                     if self.PDOsTable.GetValueByName(row, "Type") == "Transmit":
       
   433                         dir = "%I"
       
   434                     else:
       
   435                         dir = "%Q"
       
   436                     break
       
   437             location = "%s%s" % (dir, self.Controler.GetSizeOfType(data_type)) + \
       
   438                        ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation() + self.Slave + (entry_index, entry_subindex)))
       
   439             data = wx.TextDataObject(str((location, "location", data_type, var_name, "")))
       
   440             dragSource = wx.DropSource(self.VariablesGrid)
       
   441             dragSource.SetData(data)
       
   442             dragSource.DoDragDrop()
       
   443         event.Skip()
       
   444 
       
   445 [ID_CONFIGEDITOR, ID_CONFIGEDITORADDSLAVEBUTTON,
       
   446  ID_CONFIGEDITORDELETESLAVEBUTTON, ID_CONFIGEDITORSLAVENODES,
       
   447 ] = [wx.NewId() for _init_ctrls in range(4)]
       
   448 
       
   449 class ConfigEditor(EditorPanel):
       
   450     
       
   451     ID = ID_CONFIGEDITOR
       
   452     
       
   453     def _init_coll_MainSizer_Items(self, parent):
       
   454         parent.AddSizer(self.ButtonSizer, 0, border=5, flag=wx.ALIGN_RIGHT|wx.TOP|wx.LEFT|wx.RIGHT)
       
   455         parent.AddWindow(self.SlaveNodes, 0, border=5, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
       
   456 
       
   457     def _init_coll_MainSizer_Growables(self, parent):
       
   458         parent.AddGrowableCol(0)
       
   459         parent.AddGrowableRow(1)
       
   460     
       
   461     def _init_coll_ButtonSizer_Items(self, parent):
       
   462         parent.AddWindow(self.AddSlaveButton, 0, border=5, flag=wx.RIGHT)
       
   463         parent.AddWindow(self.DeleteSlaveButton, 0, border=5, flag=0)
       
   464         
       
   465     def _init_sizers(self):
       
   466         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
       
   467         self.ButtonSizer = wx.BoxSizer(wx.HORIZONTAL)
       
   468         
       
   469         self._init_coll_MainSizer_Items(self.MainSizer)
       
   470         self._init_coll_MainSizer_Growables(self.MainSizer)
       
   471         self._init_coll_ButtonSizer_Items(self.ButtonSizer)
       
   472         
       
   473         self.Editor.SetSizer(self.MainSizer)
       
   474     
       
   475     def _init_Editor(self, prnt):
       
   476         self.Editor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0), 
       
   477                 size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
   478     
       
   479         self.AddSlaveButton = wx.Button(id=ID_CONFIGEDITORADDSLAVEBUTTON, label=_('Add slave'),
       
   480               name='AddSlaveButton', parent=self.Editor, pos=wx.Point(0, 0),
       
   481               size=wx.DefaultSize, style=0)
       
   482         self.Bind(wx.EVT_BUTTON, self.OnAddSlaveButtonClick, id=ID_CONFIGEDITORADDSLAVEBUTTON)
       
   483         
       
   484         self.DeleteSlaveButton = wx.Button(id=ID_CONFIGEDITORDELETESLAVEBUTTON, label=_('Delete slave'),
       
   485               name='DeleteSlaveButton', parent=self.Editor, pos=wx.Point(0, 0),
       
   486               size=wx.DefaultSize, style=0)
       
   487         self.Bind(wx.EVT_BUTTON, self.OnDeleteSlaveButtonClick, id=ID_CONFIGEDITORDELETESLAVEBUTTON)
       
   488         
       
   489         self.SlaveNodes = wx.Notebook(id=ID_CONFIGEDITORSLAVENODES,
       
   490               name='SlaveNodes', parent=self.Editor, pos=wx.Point(0, 0),
       
   491               size=wx.Size(0, 0), style=wx.NB_LEFT)
       
   492         
       
   493         self._init_sizers()
       
   494     
       
   495     def __init__(self, parent, controler, window):
       
   496         EditorPanel.__init__(self, parent, "", window, controler)
       
   497         
       
   498         img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage()
       
   499         self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16)))
       
   500         
       
   501     def GetTitle(self):
       
   502         filename = self.Controler.GetFilename()
       
   503         if not self.Controler.ConfigIsSaved():
       
   504             return "~%s~" % filename
       
   505         return filename
       
   506     
       
   507     def GetBufferState(self):
       
   508         return self.Controler.GetBufferState()
       
   509         
       
   510     def Undo(self):
       
   511         self.Controler.LoadPrevious()
       
   512         self.RefreshView()
       
   513             
       
   514     def Redo(self):
       
   515         self.Controler.LoadNext()
       
   516         self.RefreshView()
       
   517     
       
   518     def RefreshView(self, slave_pos=None):
       
   519         slaves = self.Controler.GetSlaves()
       
   520         for i, slave in enumerate(slaves):
       
   521             if i < self.SlaveNodes.GetPageCount():
       
   522                 panel = self.SlaveNodes.GetPage(i)
       
   523                 panel.SetSlave(slave)
       
   524             else:
       
   525                 panel = SlavePanel(self.SlaveNodes, self.Controler, self, slave)
       
   526                 self.SlaveNodes.AddPage(panel, "")
       
   527         while self.SlaveNodes.GetPageCount() > len(slaves):
       
   528             self.SlaveNodes.RemovePage(len(slaves))
       
   529         self.RefreshSlaveNodesTitles()
       
   530         self.RefreshButtons()
       
   531         if slave_pos is not None:
       
   532             self.SelectSlave(slave_pos)
       
   533     
       
   534     def RefreshParentWindow(self):
       
   535         self.ParentWindow.RefreshTitle()
       
   536         self.ParentWindow.RefreshFileMenu()
       
   537         self.ParentWindow.RefreshEditMenu()
       
   538         self.ParentWindow.RefreshPageTitles()
       
   539     
       
   540     def RefreshSlaveNodesTitles(self):
       
   541         for idx in xrange(self.SlaveNodes.GetPageCount()):
       
   542             panel = self.SlaveNodes.GetPage(idx)
       
   543             self.SlaveNodes.SetPageText(idx, panel.GetSlaveTitle())
       
   544             
       
   545     def RefreshButtons(self):
       
   546         self.DeleteSlaveButton.Enable(self.SlaveNodes.GetPageCount() > 0)
       
   547     
       
   548     def SelectSlave(self, slave):
       
   549         for idx in xrange(self.SlaveNodes.GetPageCount()):
       
   550             panel = self.SlaveNodes.GetPage(idx)
       
   551             if panel.GetSlave() == slave:
       
   552                 self.SlaveNodes.SetSelection(idx)
       
   553                 return
       
   554     
       
   555     def OnAddSlaveButtonClick(self, event):
       
   556         slave = self.Controler.AddSlave()
       
   557         self.RefreshParentWindow()
       
   558         wx.CallAfter(self.RefreshView, slave)
       
   559         event.Skip()
       
   560     
       
   561     def OnDeleteSlaveButtonClick(self, event):
       
   562         selected = self.SlaveNodes.GetSelection()
       
   563         if selected != -1:
       
   564             panel = self.SlaveNodes.GetPage(selected)
       
   565             if self.Controler.RemoveSlave(panel.GetSlave()[:2]):
       
   566                 self.RefreshParentWindow()
       
   567                 wx.CallAfter(self.RefreshView)
       
   568