Package node_manager_fkie :: Module master_list_model
[frames] | no frames]

Source Code for Module node_manager_fkie.master_list_model

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Fraunhofer nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 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 
42 43 44 45 -class MasterItem(QtGui.QStandardItem):
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
71 - def _threaded_get_ip(self):
72 thread = threading.Thread(target=self.__get_ip) 73 thread.daemon = True 74 thread.start()
75
76 - def __get_ip(self):
77 try: 78 # get the IP of the master uri 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 # self.updateNameView(self.master, self.quality, self) 90 except: 91 import traceback 92 print traceback.format_exc()
93 94 95 @property
96 - def quality(self):
97 return self.__quality
98 99 @quality.setter
100 - def quality(self, value):
101 if self.__quality != value: 102 self.__quality = value 103 self.updateMasterView(self.parent_item)
104
105 - def updateMasterView(self, parent):
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 #update the name decoration 116 child = parent.child(self.row(), 0) 117 if not child is None: 118 self.updateNameView(self.master, self.quality, child)
119
120 - def updateNameView(self, master, quality, item):
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 # tooltip = ''.join([tooltip, '<b><u>Description:</u></b>']) 142 tooltip = ''.join([tooltip, item.descr]) 143 # update the icon 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
163 - def updateDescription(self, descr):
164 self.descr = descr 165 self.updateNameView(self.master, self.quality, self)
166 167 @classmethod
168 - def toHTML(cls, text):
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
183 - def type(self):
184 return MasterItem.ITEM_TYPE
185 186 @classmethod
187 - def getItemList(self, master, local):
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
205 - def __eq__(self, item):
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
212 - def __gt__(self, item):
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
219 220 221 -class MasterModel(QtGui.QStandardItemModel):
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
236 - def flags(self, index):
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 # if item and item.master.online: 248 return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled 249 return QtCore.Qt.NoItemFlags
250
251 - def updateMaster(self, master):
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 # remove master, if his name was changed but not the ROS master URI 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 # update or add a the item 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 # update item 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
289 - def updateMasterStat(self, master, quality):
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
305 - def setChecked(self, master, state):
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
321 - def removeMaster(self, master):
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
335 - def updateDescription(self, master, descr):
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