1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 from PySide import QtCore
34 from PySide import QtGui
35
36 import threading
37
38 from urlparse import urlparse
39 from socket import getaddrinfo
40
41 import node_manager_fkie as nm
46 '''
47 The master item stored in the master model. This class stores the master as
48 master_discovery_fkie.ROSMaster.
49 '''
50
51 ITEM_TYPE = QtGui.QStandardItem.UserType + 34
52
53 - def __init__(self, master, local=False, quality=None, parent=None):
54 self.name = ''.join([master.name, ' (localhost)']) if local else master.name
55 QtGui.QStandardItem.__init__(self, self.name)
56 self.parent_item = None
57 self.master = master
58 self.__quality = quality
59 self.descr = ''
60 self.ICONS = {'green' : QtGui.QIcon(":/icons/stock_connect_green.png"),
61 'yellow': QtGui.QIcon(":/icons/stock_connect_yellow.png"),
62 'red' : QtGui.QIcon(":/icons/stock_connect_red.png"),
63 'grey' : QtGui.QIcon(":/icons/stock_connect.png"),
64 'disconnected' : QtGui.QIcon(":/icons/stock_disconnect.png"),
65 'warning' : QtGui.QIcon(':/icons/crystal_clear_warning.png') }
66 self.setCheckable(True)
67 self.master_ip = None
68 self._threaded_get_ip()
69 self.updateNameView(master, quality, self)
70
72 thread = threading.Thread(target=self.__get_ip)
73 thread.daemon = True
74 thread.start()
75
77 try:
78
79 o = urlparse(self.master.uri)
80 result = getaddrinfo(o.hostname, None)
81 ips = []
82 for r in result:
83 (family, socktype, proto, canonname, (ip, port)) = r
84 if self.master_ip is None and ip:
85 self.master_ip = ''
86 if ip and not ip in ips:
87 self.master_ip = ' '.join([self.master_ip, ip])
88 ips.append(ip)
89
90 except:
91 import traceback
92 print traceback.format_exc()
93
94
95 @property
98
99 @quality.setter
104
106 '''
107 This method is called after the master state is changed to update the
108 representation of the master. The name will not be changed, but all other
109 data.
110 @param parent: Item which contains this master item. This is needed to update
111 other columns of this master.
112 @type parent: L{PySide.QtGui.QStandardItem}
113 '''
114 if not parent is None:
115
116 child = parent.child(self.row(), 0)
117 if not child is None:
118 self.updateNameView(self.master, self.quality, child)
119
121 '''
122 Updates the representation of the column contains the name state.
123 @param master: the topic data
124 @type master: master_discovery_fkie.TopicInfo
125 @param item: corresponding item in the model
126 @type item: L{TopicItem}
127 '''
128 tooltip = ''.join(['<html><body>'])
129 tooltip = ''.join([tooltip, '<h4>', master.uri, '</h4>'])
130 tooltip = ''.join([tooltip, '<dl>'])
131 tooltip = ''.join([tooltip, '<dt>', 'IP: ', str(self.master_ip), '</dt>'])
132 if master.online:
133 if not quality is None:
134 tooltip = ''.join([tooltip, '<dt>', 'Quality: ', str(quality),' %', '</dt>'])
135 if item.checkState() == QtCore.Qt.Checked:
136 tooltip = ''.join([tooltip, '<dt>', 'synchronized', '</dt>'])
137 else:
138 tooltip = ''.join([tooltip, '<dt>', 'offline', '</dt>'])
139 tooltip = ''.join([tooltip, '</dl>'])
140 if item.descr:
141
142 tooltip = ''.join([tooltip, item.descr])
143
144 if master.online:
145 if self.master_ip is None:
146 item.setIcon(self.ICONS['warning'])
147 tooltip = ''.join([tooltip, '<h4>', 'Host not reachable by name!!! The ROS topics may not by connected!!!', '</h4>'])
148 elif not quality is None:
149 if quality > 30:
150 item.setIcon(self.ICONS['green'])
151 elif quality > 5:
152 item.setIcon(self.ICONS['yellow'])
153 else:
154 item.setIcon(self.ICONS['red'])
155 else:
156 item.setIcon(self.ICONS['grey'])
157 else:
158 item.setIcon(self.ICONS['disconnected'])
159
160 tooltip = ''.join([tooltip, '</body></html>'])
161 item.setToolTip(tooltip)
162
166
167 @classmethod
169 '''
170 @param text: the text
171 @type text: C{str}
172 @return: the HTML representation of the name of the text
173 @rtype: C{str}
174 '''
175 ns, sep, name = text.rpartition('/')
176 result = ''
177 if sep:
178 result = ''.join(['<html><body>', '<span style="color:gray;">', str(ns), sep, '</span><b>', name, '</b></body></html>'])
179 else:
180 result = name
181 return result
182
185
186 @classmethod
188 '''
189 Creates the list of the items from master. This list is used for the
190 visualization of master data as a table row.
191 @param master the master data
192 @type master master_discovery_fkie.ROSMaster
193 @param local: whether the master is local or not
194 @type local: bool
195 @return: the list for the representation as a row
196 @rtype: C{[L{MasterItem} or L{PySide.QtGui.QStandardItem}, ...]}
197 '''
198 items = []
199 item = MasterItem(master, local)
200 items.append(item)
201 return items
202
203
204
206 if isinstance(item, str) or isinstance(item, unicode):
207 return self.master.name.lower() == item.lower()
208 elif not (item is None):
209 return self.master.name.lower() == item.master.name.lower()
210 return False
211
213 if isinstance(item, str) or isinstance(item, unicode):
214 return self.master.name.lower() > item.lower()
215 elif not (item is None):
216 return self.master.name.lower() > item.master.name.lower()
217 return False
218
222 '''
223 The model to manage the list with masters in ROS network.
224 '''
225 header = [('Name', -1)]
226 '''@ivar: the list with columns C{[(name, width), ...]}'''
227
228 - def __init__(self, local_masteruri=None):
229 '''
230 Creates a new list model.
231 '''
232 QtGui.QStandardItemModel.__init__(self)
233 self.setColumnCount(len(MasterModel.header))
234 self._masteruri = local_masteruri
235
237 '''
238 @param index: parent of the list
239 @type index: L{PySide.QtCore.QModelIndex}
240 @return: Flag or the requestet item
241 @rtype: L{PySide.QtCore.Qt.ItemFlag}
242 @see: U{http://www.pyside.org/docs/pyside-1.0.1/PySide/QtCore/Qt.html}
243 '''
244 if not index.isValid():
245 return QtCore.Qt.NoItemFlags
246 item = self.itemFromIndex(index)
247
248 return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
249 return QtCore.Qt.NoItemFlags
250
252 '''
253 Updates the information of the ros master. If the ROS master not exists, it
254 will be added.
255
256 @param master: the ROS master to update
257 @type master: L{master_discovery_fkie.msg.ROSMaster}
258 '''
259
260 root = self.invisibleRootItem()
261 for i in reversed(range(root.rowCount())):
262 masterItem = root.child(i)
263 if masterItem.master.uri == master.uri and masterItem.master.name != master.name:
264 root.removeRow(i)
265 break
266
267
268 root = self.invisibleRootItem()
269 doAddItem = True
270 for i in range(root.rowCount()):
271 masterItem = root.child(i)
272 if (masterItem == master.name):
273
274 masterItem.master = master
275 masterItem.updateMasterView(root)
276 doAddItem = False
277 break
278 elif (masterItem > master.name):
279 mitem = MasterItem.getItemList(master, (nm.is_local(nm.nameres().getHostname(master.uri))))
280 root.insertRow(i, mitem)
281 mitem[0].parent_item = root
282 doAddItem = False
283 break
284 if doAddItem:
285 mitem = MasterItem.getItemList(master, (nm.is_local(nm.nameres().getHostname(master.uri))))
286 root.appendRow(mitem)
287 mitem[0].parent_item = root
288
290 '''
291 Updates the information of the ros master.
292
293 @param master: the ROS master to update
294 @type master: C{str}
295 @param quality: the quality of the connection to master
296 @type quality: C{float}
297 '''
298 root = self.invisibleRootItem()
299 for i in reversed(range(root.rowCount())):
300 masterItem = root.child(i)
301 if masterItem.master.name in master:
302 masterItem.quality = quality
303 break
304
306 '''
307 Set the master to checked state
308
309 @param master: the ROS master to update
310 @type master: C{str}
311 @param state: new state
312 @type state: C{bool}
313 '''
314 root = self.invisibleRootItem()
315 for i in reversed(range(root.rowCount())):
316 masterItem = root.child(i)
317 if masterItem.master.name in master:
318 masterItem.setCheckState(QtCore.Qt.Checked if state else QtCore.Qt.Unchecked)
319 break
320
322 '''
323 Remove the master with given name.
324
325 @param master: the ROS master to add
326 @type master: C{str}
327 '''
328 root = self.invisibleRootItem()
329 for i in reversed(range(root.rowCount())):
330 masterItem = root.child(i)
331 if masterItem.master.name == master:
332 root.removeRow(i)
333 break
334
336 '''
337 Updates the description of the master with given name.
338
339 @param master: the ROS master to add
340 @type master: C{str}
341 @param descr: the description of the master coded as HTML
342 @type descr: C{str}
343 '''
344 root = self.invisibleRootItem()
345 for i in reversed(range(root.rowCount())):
346 masterItem = root.child(i)
347 if masterItem.master.name == master:
348 masterItem.updateDescription(descr)
349