dialogs/DiscoveryDialog.py
changeset 1784 64beb9e9c749
parent 1773 38fde37c3766
child 1830 e598d1acf354
equal deleted inserted replaced
1729:31e63e25b4cc 1784:64beb9e9c749
    23 # along with this program; if not, write to the Free Software
    23 # along with this program; if not, write to the Free Software
    24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    24 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    25 
    25 
    26 import socket
    26 import socket
    27 import wx
    27 import wx
    28 import  wx.lib.mixins.listctrl  as  listmix
    28 import wx.lib.mixins.listctrl as listmix
    29 from util.Zeroconf import *
    29 from util.Zeroconf import *
    30 
    30 
    31 import connectors
    31 import connectors
    32 
    32 
    33 service_type = '_PYRO._tcp.local.'
    33 service_type = '_PYRO._tcp.local.'
       
    34 
    34 
    35 
    35 class AutoWidthListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    36 class AutoWidthListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    36     def __init__(self, parent, id, name, pos=wx.DefaultPosition,
    37     def __init__(self, parent, id, name, pos=wx.DefaultPosition,
    37                  size=wx.DefaultSize, style=0):
    38                  size=wx.DefaultSize, style=0):
    38         wx.ListCtrl.__init__(self, parent, id, pos, size, style, name=name)
    39         wx.ListCtrl.__init__(self, parent, id, pos, size, style, name=name)
    39         listmix.ListCtrlAutoWidthMixin.__init__(self)
    40         listmix.ListCtrlAutoWidthMixin.__init__(self)
    40 
    41 
    41 [ID_DISCOVERYDIALOG, ID_DISCOVERYDIALOGSTATICTEXT1, 
    42 
    42  ID_DISCOVERYDIALOGSERVICESLIST, ID_DISCOVERYDIALOGREFRESHBUTTON, 
    43 [
    43  ID_DISCOVERYDIALOGLOCALBUTTON, ID_DISCOVERYDIALOGIPBUTTON, 
    44     ID_DISCOVERYDIALOG, ID_DISCOVERYDIALOGSTATICTEXT1,
       
    45     ID_DISCOVERYDIALOGSERVICESLIST, ID_DISCOVERYDIALOGREFRESHBUTTON,
       
    46     ID_DISCOVERYDIALOGLOCALBUTTON, ID_DISCOVERYDIALOGIPBUTTON,
    44 ] = [wx.NewId() for _init_ctrls in range(6)]
    47 ] = [wx.NewId() for _init_ctrls in range(6)]
    45 
    48 
       
    49 
    46 class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin):
    50 class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin):
    47     
    51 
    48     def _init_coll_MainSizer_Items(self, parent):
    52     def _init_coll_MainSizer_Items(self, parent):
    49         parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW)
    53         parent.AddWindow(self.staticText1,    0, border=20, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW)
    50         parent.AddWindow(self.ServicesList, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW)
    54         parent.AddWindow(self.ServicesList,   0, border=20, flag=wx.LEFT | wx.RIGHT | wx.GROW)
    51         parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW)
    55         parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW)
    52         
    56 
    53     def _init_coll_MainSizer_Growables(self, parent):
    57     def _init_coll_MainSizer_Growables(self, parent):
    54         parent.AddGrowableCol(0)
    58         parent.AddGrowableCol(0)
    55         parent.AddGrowableRow(1)
    59         parent.AddGrowableRow(1)
    56     
    60 
    57     def _init_coll_ButtonGridSizer_Items(self, parent):
    61     def _init_coll_ButtonGridSizer_Items(self, parent):
    58         parent.AddWindow(self.RefreshButton, 0, border=0, flag=0)
    62         parent.AddWindow(self.RefreshButton, 0, border=0, flag=0)
    59         parent.AddWindow(self.LocalButton, 0, border=0, flag=0)
    63         parent.AddWindow(self.LocalButton, 0, border=0, flag=0)
    60         parent.AddWindow(self.IpButton, 0, border=0, flag=0)
    64         parent.AddWindow(self.IpButton, 0, border=0, flag=0)
    61         parent.AddSizer(self.ButtonSizer, 0, border=0, flag=0)
    65         parent.AddSizer(self.ButtonSizer, 0, border=0, flag=0)
    62         
    66 
    63     def _init_coll_ButtonGridSizer_Growables(self, parent):
    67     def _init_coll_ButtonGridSizer_Growables(self, parent):
    64         parent.AddGrowableCol(0)
    68         parent.AddGrowableCol(0)
    65         parent.AddGrowableCol(1)
    69         parent.AddGrowableCol(1)
    66         parent.AddGrowableRow(0)
    70         parent.AddGrowableRow(0)
    67     
    71 
    68     def _init_sizers(self):
    72     def _init_sizers(self):
    69         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
    73         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
    70         self.ButtonGridSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=1, vgap=0)
    74         self.ButtonGridSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=1, vgap=0)
    71         
    75 
    72         self._init_coll_MainSizer_Items(self.MainSizer)
    76         self._init_coll_MainSizer_Items(self.MainSizer)
    73         self._init_coll_MainSizer_Growables(self.MainSizer)
    77         self._init_coll_MainSizer_Growables(self.MainSizer)
    74         self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer)
    78         self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer)
    75         self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer)
    79         self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer)
    76         
    80 
    77         self.SetSizer(self.MainSizer)
    81         self.SetSizer(self.MainSizer)
    78     
    82 
    79     def _init_ctrls(self, prnt):
    83     def _init_ctrls(self, prnt):
    80         wx.Dialog.__init__(self, id=ID_DISCOVERYDIALOG, 
    84         wx.Dialog.__init__(
    81               name='DiscoveryDialog', parent=prnt, style=wx.DEFAULT_DIALOG_STYLE,
    85             self, id=ID_DISCOVERYDIALOG,
    82               title=_('Service Discovery'))
    86             name='DiscoveryDialog', parent=prnt, style=wx.DEFAULT_DIALOG_STYLE,
    83         
    87             title=_('Service Discovery'))
    84         self.staticText1 = wx.StaticText(id=ID_DISCOVERYDIALOGSTATICTEXT1,
    88 
    85               label=_('Services available:'), name='staticText1', parent=self,
    89         self.staticText1 = wx.StaticText(
    86               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
    90             id=ID_DISCOVERYDIALOGSTATICTEXT1,
    87         
    91             label=_('Services available:'), name='staticText1', parent=self,
       
    92             pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
       
    93 
    88         # Set up list control
    94         # Set up list control
    89         self.ServicesList = AutoWidthListCtrl(id=ID_DISCOVERYDIALOGSERVICESLIST,
    95         self.ServicesList = AutoWidthListCtrl(
    90               name='ServicesList', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0), 
    96             id=ID_DISCOVERYDIALOGSERVICESLIST,
    91               style=wx.LC_REPORT|wx.LC_EDIT_LABELS|wx.LC_SORT_ASCENDING|wx.LC_SINGLE_SEL)
    97             name='ServicesList', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0),
       
    98             style=wx.LC_REPORT | wx.LC_EDIT_LABELS | wx.LC_SORT_ASCENDING | wx.LC_SINGLE_SEL)
    92         self.ServicesList.InsertColumn(0, _('NAME'))
    99         self.ServicesList.InsertColumn(0, _('NAME'))
    93         self.ServicesList.InsertColumn(1, _('TYPE'))
   100         self.ServicesList.InsertColumn(1, _('TYPE'))
    94         self.ServicesList.InsertColumn(2, _('IP'))
   101         self.ServicesList.InsertColumn(2, _('IP'))
    95         self.ServicesList.InsertColumn(3, _('PORT'))
   102         self.ServicesList.InsertColumn(3, _('PORT'))
    96         self.ServicesList.SetColumnWidth(0, 150)
   103         self.ServicesList.SetColumnWidth(0, 150)
    98         self.ServicesList.SetColumnWidth(2, 150)
   105         self.ServicesList.SetColumnWidth(2, 150)
    99         self.ServicesList.SetColumnWidth(3, 150)
   106         self.ServicesList.SetColumnWidth(3, 150)
   100         self.ServicesList.SetInitialSize(wx.Size(-1, 300))
   107         self.ServicesList.SetInitialSize(wx.Size(-1, 300))
   101         self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, id=ID_DISCOVERYDIALOGSERVICESLIST)
   108         self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, id=ID_DISCOVERYDIALOGSERVICESLIST)
   102         self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, id=ID_DISCOVERYDIALOGSERVICESLIST)
   109         self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, id=ID_DISCOVERYDIALOGSERVICESLIST)
   103         
   110 
   104         listmix.ColumnSorterMixin.__init__(self, 4)
   111         listmix.ColumnSorterMixin.__init__(self, 4)
   105         
   112 
   106         self.RefreshButton = wx.Button(id=ID_DISCOVERYDIALOGREFRESHBUTTON,
   113         self.RefreshButton = wx.Button(
   107               label=_('Refresh'), name='RefreshButton', parent=self,
   114             id=ID_DISCOVERYDIALOGREFRESHBUTTON,
   108               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   115             label=_('Refresh'), name='RefreshButton', parent=self,
       
   116             pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   109         self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, id=ID_DISCOVERYDIALOGREFRESHBUTTON)
   117         self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, id=ID_DISCOVERYDIALOGREFRESHBUTTON)
   110         
   118 
   111         self.LocalButton = wx.Button(id=ID_DISCOVERYDIALOGLOCALBUTTON,
   119         self.LocalButton = wx.Button(
   112               label=_('Local'), name='LocalButton', parent=self,
   120             id=ID_DISCOVERYDIALOGLOCALBUTTON,
   113               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   121             label=_('Local'), name='LocalButton', parent=self,
       
   122             pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   114         self.Bind(wx.EVT_BUTTON, self.OnLocalButton, id=ID_DISCOVERYDIALOGLOCALBUTTON)
   123         self.Bind(wx.EVT_BUTTON, self.OnLocalButton, id=ID_DISCOVERYDIALOGLOCALBUTTON)
   115 
   124 
   116         self.IpButton = wx.Button(id=ID_DISCOVERYDIALOGIPBUTTON,
   125         self.IpButton = wx.Button(
   117               label=_('Add IP'), name='IpButton', parent=self,
   126             id=ID_DISCOVERYDIALOGIPBUTTON,
   118               pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   127             label=_('Add IP'), name='IpButton', parent=self,
       
   128             pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
   119         self.Bind(wx.EVT_BUTTON, self.OnIpButton, id=ID_DISCOVERYDIALOGIPBUTTON)
   129         self.Bind(wx.EVT_BUTTON, self.OnIpButton, id=ID_DISCOVERYDIALOGIPBUTTON)
   120         
   130 
   121         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTER)
   131         self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTER)
   122         
   132 
   123         self._init_sizers()
   133         self._init_sizers()
   124         self.Fit()
   134         self.Fit()
   125         
   135 
   126     def __init__(self, parent):
   136     def __init__(self, parent):
   127         self._init_ctrls(parent)
   137         self._init_ctrls(parent)
   128         
   138 
   129         self.itemDataMap = {}
   139         self.itemDataMap = {}
   130         self.nextItemId = 0
   140         self.nextItemId = 0
   131         
   141 
   132         self.URI = None
   142         self.URI = None
   133         self.Browser = None
   143         self.Browser = None
   134         
   144 
   135         self.ZeroConfInstance = Zeroconf()
   145         self.ZeroConfInstance = Zeroconf()
   136         self.RefreshList()
   146         self.RefreshList()
   137         self.LatestSelection=None
   147         self.LatestSelection = None
   138         
   148 
   139     def __del__(self):
   149     def __del__(self):
   140         if self.Browser is not None : self.Browser.cancel()
   150         if self.Browser is not None:
       
   151             self.Browser.cancel()
   141         self.ZeroConfInstance.close()
   152         self.ZeroConfInstance.close()
   142         
   153 
   143     def RefreshList(self):
   154     def RefreshList(self):
   144         if self.Browser is not None : self.Browser.cancel()
   155         if self.Browser is not None:
       
   156             self.Browser.cancel()
   145         self.Browser = ServiceBrowser(self.ZeroConfInstance, service_type, self)
   157         self.Browser = ServiceBrowser(self.ZeroConfInstance, service_type, self)
   146 
   158 
   147     def OnRefreshButton(self, event):
   159     def OnRefreshButton(self, event):
   148         self.ServicesList.DeleteAllItems()
   160         self.ServicesList.DeleteAllItems()
   149         self.RefreshList()
   161         self.RefreshList()
   152         self.URI = "LOCAL://"
   164         self.URI = "LOCAL://"
   153         self.EndModal(wx.ID_OK)
   165         self.EndModal(wx.ID_OK)
   154         event.Skip()
   166         event.Skip()
   155 
   167 
   156     def OnIpButton(self, event):
   168     def OnIpButton(self, event):
       
   169         def GetColText(col):
       
   170             return self.getColumnText(self.LatestSelection, col)
       
   171 
   157         if self.LatestSelection is not None:
   172         if self.LatestSelection is not None:
   158             l = lambda col : self.getColumnText(self.LatestSelection,col)
   173             self.URI = "%s://%s:%s" % tuple(map(GetColText, (1, 2, 3)))
   159             self.URI = "%s://%s:%s"%tuple(map(l,(1,2,3)))
       
   160             self.EndModal(wx.ID_OK)
   174             self.EndModal(wx.ID_OK)
   161         event.Skip()
   175         event.Skip()
   162 
   176 
   163     # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
   177     # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
   164     def GetListCtrl(self):
   178     def GetListCtrl(self):
   179 
   193 
   180 #    def SetURI(self, idx):
   194 #    def SetURI(self, idx):
   181 #        connect_type = self.getColumnText(idx, 1)
   195 #        connect_type = self.getColumnText(idx, 1)
   182 #        connect_address = self.getColumnText(idx, 2)
   196 #        connect_address = self.getColumnText(idx, 2)
   183 #        connect_port = self.getColumnText(idx, 3)
   197 #        connect_port = self.getColumnText(idx, 3)
   184 #        
   198 #
   185 #        self.URI = "%s://%s:%s"%(connect_type, connect_address, connect_port)
   199 #        self.URI = "%s://%s:%s"%(connect_type, connect_address, connect_port)
   186 
   200 
   187     def SetURI(self, idx):
   201     def SetURI(self, idx):
   188         self.LatestSelection = idx
   202         self.LatestSelection = idx
   189         svcname = self.getColumnText(idx, 0) 
   203         svcname = self.getColumnText(idx, 0)
   190         connect_type = self.getColumnText(idx, 1)
   204         connect_type = self.getColumnText(idx, 1)
   191         self.URI = "%s://%s"%(connect_type, svcname + '.' + service_type)
   205         self.URI = "%s://%s" % (connect_type, svcname + '.' + service_type)
   192         
   206 
   193     def GetURI(self):
   207     def GetURI(self):
   194         return self.URI
   208         return self.URI
   195         
   209 
   196     def removeService(self, zeroconf, _type, name):
   210     def removeService(self, zeroconf, _type, name):
   197         wx.CallAfter(self._removeService, name)
   211         wx.CallAfter(self._removeService, name)
   198 
   212 
   199 
       
   200     def _removeService(self, name):
   213     def _removeService(self, name):
   201         '''
   214         '''
   202         called when a service with the desired type goes offline.
   215         called when a service with the desired type goes offline.
   203         '''
   216         '''
   204         
   217 
   205         # loop through the list items looking for the service that went offline
   218         # loop through the list items looking for the service that went offline
   206         for idx in xrange(self.ServicesList.GetItemCount()):
   219         for idx in xrange(self.ServicesList.GetItemCount()):
   207             # this is the unique identifier assigned to the item
   220             # this is the unique identifier assigned to the item
   208             item_id = self.ServicesList.GetItemData(idx)
   221             item_id = self.ServicesList.GetItemData(idx)
   209 
   222 
   211             item_name = self.itemDataMap[item_id][4]
   224             item_name = self.itemDataMap[item_id][4]
   212 
   225 
   213             if item_name == name:
   226             if item_name == name:
   214                 self.ServicesList.DeleteItem(idx)
   227                 self.ServicesList.DeleteItem(idx)
   215                 break
   228                 break
   216         
   229 
   217     def addService(self, zeroconf, _type, name):
   230     def addService(self, zeroconf, _type, name):
   218         wx.CallAfter(self._addService, _type, name)
   231         wx.CallAfter(self._addService, _type, name)
   219 
   232 
   220     def _addService(self, _type, name):
   233     def _addService(self, _type, name):
   221         '''
   234         '''
   222         called when a service with the desired type is discovered.
   235         called when a service with the desired type is discovered.
   223         '''
   236         '''
   224         info = self.ZeroConfInstance.getServiceInfo(_type, name)
   237         info = self.ZeroConfInstance.getServiceInfo(_type, name)
   225 
   238 
   226         svcname  = name.split(".")[0]
   239         svcname = name.split(".")[0]
   227         typename = _type.split(".")[0][1:]
   240         typename = _type.split(".")[0][1:]
   228         ip       = str(socket.inet_ntoa(info.getAddress()))
   241         ip = str(socket.inet_ntoa(info.getAddress()))
   229         port     = info.getPort()
   242         port = info.getPort()
   230 
   243 
   231         num_items = self.ServicesList.GetItemCount()
   244         num_items = self.ServicesList.GetItemCount()
   232 
   245 
   233         # display the new data in the list
   246         # display the new data in the list
   234         new_item = self.ServicesList.InsertStringItem(num_items, svcname)
   247         new_item = self.ServicesList.InsertStringItem(num_items, svcname)
   238 
   251 
   239         # record the new data for the ColumnSorterMixin
   252         # record the new data for the ColumnSorterMixin
   240         # we assign every list item a unique id (that won't change when items
   253         # we assign every list item a unique id (that won't change when items
   241         # are added or removed)
   254         # are added or removed)
   242         self.ServicesList.SetItemData(new_item, self.nextItemId)
   255         self.ServicesList.SetItemData(new_item, self.nextItemId)
   243  
   256 
   244         # the value of each column has to be stored in the itemDataMap
   257         # the value of each column has to be stored in the itemDataMap
   245         # so that ColumnSorterMixin knows how to sort the column.
   258         # so that ColumnSorterMixin knows how to sort the column.
   246 
   259 
   247         # "name" is included at the end so that self.removeService
   260         # "name" is included at the end so that self.removeService
   248         # can access it.
   261         # can access it.
   249         self.itemDataMap[self.nextItemId] = [ svcname, typename, ip, port, name ]
   262         self.itemDataMap[self.nextItemId] = [svcname, typename, ip, port, name]
   250 
   263 
   251         self.nextItemId += 1
   264         self.nextItemId += 1
   252