25 import wx |
24 import wx |
26 from Zeroconf import * |
25 from Zeroconf import * |
27 import socket |
26 import socket |
28 import wx.lib.mixins.listctrl as listmix |
27 import wx.lib.mixins.listctrl as listmix |
29 |
28 |
30 class TestListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): |
29 class AutoWidthListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): |
31 def __init__(self, parent, ID, pos=wx.DefaultPosition, |
30 def __init__(self, parent, ID, pos=wx.DefaultPosition, |
32 size=wx.DefaultSize, style=0): |
31 size=wx.DefaultSize, style=0): |
33 wx.ListCtrl.__init__(self, parent, ID, pos, size, style) |
32 wx.ListCtrl.__init__(self, parent, ID, pos, size, style) |
34 listmix.ListCtrlAutoWidthMixin.__init__(self) |
33 listmix.ListCtrlAutoWidthMixin.__init__(self) |
35 |
34 |
36 class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin): |
35 class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin): |
37 def __init__(self, parent, id=-1, title='Service Discovery'): |
36 def __init__(self, parent, id=-1, title='Service Discovery'): |
38 self.my_result=None |
37 self.my_result=None |
39 wx.Dialog.__init__(self, parent, id, title, size=(600,600), style=wx.DEFAULT_DIALOG_STYLE) |
38 wx.Dialog.__init__(self, parent, id, title, size=(600,600), style=wx.DEFAULT_DIALOG_STYLE) |
40 |
39 |
|
40 # set up dialog sizer |
|
41 |
41 sizer = wx.FlexGridSizer(2, 1, 2, 2) # rows, cols, vgap, hgap |
42 sizer = wx.FlexGridSizer(2, 1, 2, 2) # rows, cols, vgap, hgap |
42 sizer.AddGrowableRow(0) |
43 sizer.AddGrowableRow(0) |
43 sizer.AddGrowableCol(0) |
44 sizer.AddGrowableCol(0) |
44 |
45 |
45 self.list = TestListCtrl(self, -1, |
46 # set up list control |
46 #pos=(50,20), |
47 |
47 #size=(500,300), |
48 self.list = AutoWidthListCtrl(self, -1, |
48 style=wx.LC_REPORT |
49 #pos=(50,20), |
49 | wx.LC_EDIT_LABELS |
50 #size=(500,300), |
50 | wx.LC_SORT_ASCENDING |
51 style=wx.LC_REPORT |
51 ) |
52 | wx.LC_EDIT_LABELS |
|
53 | wx.LC_SORT_ASCENDING |
|
54 | wx.LC_SINGLE_SEL |
|
55 ) |
52 sizer.Add(self.list, 1, wx.EXPAND) |
56 sizer.Add(self.list, 1, wx.EXPAND) |
53 |
57 |
54 btsizer = wx.FlexGridSizer(1, 6, 2, 2) # rows, cols, vgap, hgap |
58 btsizer = wx.FlexGridSizer(1, 6, 2, 2) # rows, cols, vgap, hgap |
55 |
59 |
56 sizer.Add(btsizer, 1, wx.EXPAND) |
60 sizer.Add(btsizer, 1, wx.EXPAND) |
58 self.PopulateList() |
62 self.PopulateList() |
59 |
63 |
60 self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) |
64 self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) |
61 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.list) |
65 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.list) |
62 |
66 |
|
67 # set up buttons |
|
68 |
63 local_id = wx.NewId() |
69 local_id = wx.NewId() |
64 b = wx.Button(self, local_id, "Refresh") |
70 b = wx.Button(self, local_id, "Refresh") |
65 self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, b) |
71 self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, b) |
66 btsizer.Add(b) |
72 btsizer.Add(b) |
67 |
73 |
87 |
93 |
88 self.SetSizer(sizer) |
94 self.SetSizer(sizer) |
89 |
95 |
90 listmix.ColumnSorterMixin.__init__(self, 4) |
96 listmix.ColumnSorterMixin.__init__(self, 4) |
91 |
97 |
92 #type = "_http._tcp.local." |
98 # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py |
|
99 self.itemDataMap = {} |
|
100 |
|
101 # a counter used to assign a unique id to each listctrl item |
|
102 self.nextItemId = 0 |
|
103 |
93 self.browser = None |
104 self.browser = None |
94 self.zConfInstance = Zeroconf() |
105 self.zConfInstance = Zeroconf() |
95 self.RefreshList() |
106 self.RefreshList() |
96 |
107 |
97 self.Bind(wx.EVT_CLOSE, self.OnClose) |
108 self.Bind(wx.EVT_CLOSE, self.OnClose) |
98 |
109 |
99 def RefreshList(self): |
110 def RefreshList(self): |
100 type = "_PYRO._tcp.local." |
111 type = "_WGPLC._tcp.local." |
101 self.browser = ServiceBrowser(self.zConfInstance, type, self) |
112 self.browser = ServiceBrowser(self.zConfInstance, type, self) |
102 |
113 |
103 def OnRefreshButton(self, event): |
114 def OnRefreshButton(self, event): |
104 self.list.DeleteAllItems() |
115 self.list.DeleteAllItems() |
105 self.browser.cancel() |
116 self.browser.cancel() |
156 |
167 |
157 def GetResult(self): |
168 def GetResult(self): |
158 return self.my_result |
169 return self.my_result |
159 |
170 |
160 def removeService(self, zeroconf, type, name): |
171 def removeService(self, zeroconf, type, name): |
161 pass |
172 ''' |
|
173 called when a service with the desired type goes offline. |
|
174 ''' |
|
175 |
|
176 # loop through the list items looking for the service that went offline |
|
177 for idx in xrange(self.list.GetItemCount()): |
|
178 # this is the unique identifier assigned to the item |
|
179 item_id = self.list.GetItemData(idx) |
|
180 |
|
181 # this is the full typename that was received by addService |
|
182 item_name = self.itemDataMap[item_id][4] |
|
183 |
|
184 if item_name == name: |
|
185 self.list.DeleteItem(idx) |
|
186 break |
162 |
187 |
163 def addService(self, zeroconf, type, name): |
188 def addService(self, zeroconf, type, name): |
|
189 ''' |
|
190 called when a service with the desired type is discovered. |
|
191 ''' |
|
192 |
164 info = self.zConfInstance.getServiceInfo(type, name) |
193 info = self.zConfInstance.getServiceInfo(type, name) |
165 |
194 |
166 svcname = name.split(".")[0] |
195 svcname = name.split(".")[0] |
167 typename = type.split(".")[0][1:] |
196 typename = type.split(".")[0][1:] |
168 ip = str(socket.inet_ntoa(info.getAddress())) |
197 ip = str(socket.inet_ntoa(info.getAddress())) |
169 port = info.getPort() |
198 port = info.getPort() |
170 |
199 |
171 num_items = self.list.GetItemCount() |
200 num_items = self.list.GetItemCount() |
|
201 |
|
202 # display the new data in the list |
172 new_item = self.list.InsertStringItem(num_items, svcname) |
203 new_item = self.list.InsertStringItem(num_items, svcname) |
173 self.list.SetStringItem(new_item, 1, "%s" % typename) |
204 self.list.SetStringItem(new_item, 1, "%s" % typename) |
174 self.list.SetStringItem(new_item, 2, "%s" % ip) |
205 self.list.SetStringItem(new_item, 2, "%s" % ip) |
175 self.list.SetStringItem(new_item, 3, "%s" % info.getPort()) |
206 self.list.SetStringItem(new_item, 3, "%s" % port) |
|
207 |
|
208 # record the new data for the ColumnSorterMixin |
|
209 # we assign every list item a unique id (that won't change when items |
|
210 # are added or removed) |
|
211 self.list.SetItemData(new_item, self.nextItemId) |
|
212 |
|
213 # the value of each column has to be stored in the itemDataMap |
|
214 # so that ColumnSorterMixin knows how to sort the column. |
|
215 |
|
216 # "name" is included at the end so that self.removeService |
|
217 # can access it. |
|
218 self.itemDataMap[self.nextItemId] = [ svcname, typename, ip, port, name ] |
|
219 |
|
220 self.nextItemId += 1 |
176 |
221 |
177 def CreateURI(self, connect_type, connect_address, connect_port): |
222 def CreateURI(self, connect_type, connect_address, connect_port): |
178 uri = "%s://%s:%s"%(connect_type, connect_address, connect_port) |
223 uri = "%s://%s:%s"%(connect_type, connect_address, connect_port) |
179 return uri |
224 return uri |
180 |
225 |