Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 import os
00036
00037 import roslib;roslib.load_manifest('rqt_robot_monitor')
00038 import rospy
00039 from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus
00040 from python_qt_binding.QtGui import QTreeWidgetItem
00041
00042 from .inspector_window import InspectorWindow
00043 from .util_robot_monitor import Util
00044
00045 class StatusItem(QTreeWidgetItem):
00046 """
00047 Represents a single tree node that is capable of holding children objects
00048 of its class type.
00049 """
00050
00051 def __init__(self, status):
00052 '''
00053 @param status: DiagnosticStatus
00054 '''
00055 super(StatusItem, self).__init__(QTreeWidgetItem.UserType)
00056
00057 self._children_statusitems = []
00058 self.name = status.name
00059 self.level = status.level
00060 self.last_level = None
00061 self.inspector = None
00062 self.status = status
00063
00064 self.warning_id = None
00065 self.error_id = None
00066
00067 self.setText(0, '/' + Util.get_nice_name(self.name))
00068
00069 def get_name(self):
00070 return self.name
00071
00072 def enable(self):
00073 if self.inspector:
00074 self.inspector.enable()
00075
00076 def disable(self):
00077 if self.inspector:
00078 self.inspector.disable()
00079
00080 '''
00081 Replace old status with the passed one.
00082
00083 @param status: DiagnosticsStatus
00084 '''
00085 def update(self, status):
00086 self.status = status
00087
00088 def update_children(self, status_new, diag_array):
00089 """
00090
00091 Recursive for tree node's children.
00092 Update text on treeWidgetItem, set icon on it.
00093
00094 @param status: DiagnosticStatus
00095 @param msg: DiagnosticArray
00096 """
00097
00098 self.status = status_new
00099
00100 if self.inspector:
00101 self.inspector.update_status_display(self.status)
00102
00103 children_diag_statuses = Util.get_children(self.name, diag_array)
00104
00105 names_toplevel_local = [s.name for s in self._children_statusitems]
00106 new_statusitems = []
00107 remove = []
00108 errors = 0
00109 warnings = 0
00110 for child_diagnostic_status in children_diag_statuses:
00111 name = child_diagnostic_status.name
00112 device_name = Util.get_nice_name(child_diagnostic_status.name)
00113 headline = "%s : %s" % (child_diagnostic_status.name,
00114 child_diagnostic_status.message)
00115
00116 headline_msg = ''
00117 if (child_diagnostic_status.level != DiagnosticStatus.OK):
00118 headline_msg = Util.gen_headline_warn_or_err(child_diagnostic_status)
00119 if (child_diagnostic_status.level == DiagnosticStatus.ERROR):
00120 errors = errors + 1
00121 elif (child_diagnostic_status.level == DiagnosticStatus.WARN):
00122 warnings = warnings + 1
00123 else:
00124 headline_msg = Util.gen_headline_status_green(child_diagnostic_status)
00125 rospy.logdebug(' update_children level= %s',
00126 child_diagnostic_status.level)
00127
00128 if name in names_toplevel_local:
00129 index_child = names_toplevel_local.index(name)
00130 status_item = self._children_statusitems[ index_child ]
00131 status_item.update_children(child_diagnostic_status, diag_array)
00132 Util._update_status_images(child_diagnostic_status, status_item)
00133 rospy.logdebug(' StatusItem update 33 index= %d dev_name= %s',
00134 index_child, device_name)
00135
00136 status_item.setText(0, device_name)
00137 status_item.setText(1, child_diagnostic_status.message)
00138 elif len(self.strip_child(name).split('/')) <= 2:
00139 status_item = StatusItem(child_diagnostic_status)
00140 status_item.update_children(child_diagnostic_status,
00141 diag_array)
00142
00143 status_item.setText(0, device_name)
00144 status_item.setText(1, child_diagnostic_status.message)
00145 self._children_statusitems.append(status_item)
00146
00147 self.addChild(status_item)
00148
00149 rospy.logdebug(' ------ Statusitem.update_children err=%d warn=%d',
00150 errors, warnings)
00151 return {Util._DICTKEY_TIMES_ERROR : errors,
00152 Util._DICTKEY_TIMES_WARN : warnings}
00153
00154 def on_click(self):
00155 if not self.inspector:
00156 self.inspector = InspectorWindow(self.status,
00157 self.close_inspector_window)
00158 else:
00159 self.inspector.activateWindow()
00160
00161 '''
00162 @author: Isaac Saito
00163 '''
00164 def close_inspector_window(self):
00165 rospy.logdebug(' ------ Statusitem close_inspector_window 1')
00166 self.inspector = None
00167
00168 def strip_child(self, child):
00169 return child.replace(self.name, '')
00170
00171 def close(self):
00172 """
00173 Because Isaac failed to find a way to call a destructor of a class in
00174 python in general, he made this function, intending it to be called by
00175 its parent object (in this case RobotMonitorWidget's instance)
00176 every timeline when a certain node gets removed.
00177
00178 @author: Isaac Saito
00179 """
00180 if self.inspector:
00181
00182 self.inspector.close()
00183
00184
00185 for status_item in self._children_statusitems:
00186 status_item.close()
00187
00188 class InstantaneousState(object):
00189 """
00190 A container for StatusItem per timeframe (second).
00191
00192 Copied from robot_monitor.
00193 """
00194 def __init__(self):
00195 self._items = {}
00196 self._msg = None
00197 self._has_warned_no_name = False
00198
00199 def reset(self):
00200 self._items = {}
00201 self._msg = None
00202
00203 def get_parent(self, item):
00204 parent_name = get_parent_name(item.status.name)
00205
00206 if (parent_name not in self._items):
00207 return None
00208
00209 return self._items[parent_name]
00210
00211 def get_descendants(self, item):
00212 rospy.logdebug(' Status get_descendants status.name=%s',
00213 item.status.name)
00214 child_keys = [k for k in self._items.iterkeys()
00215 if k.startswith(item.status.name + "/")]
00216 children = [self._items[k] for k in child_keys]
00217 return children
00218
00219 def get_items(self):
00220 return self._items
00221
00222 def update(self, msg):
00223 """
00224
00225 @param msg: DiagnosticArray
00226
00227 Copied from robot_monitor.
00228 """
00229
00230 removed = []
00231 added = []
00232 items = {}
00233
00234
00235
00236 for s in msg.status:
00237
00238 if not s.name and not self._has_warned_no_name:
00239 rospy.logwarn('DiagnosticStatus message with no "name". ' +
00240 'Unable to add to robot monitor. Message: ' +
00241 '%s, hardware ID: %s, level: %d' %
00242 (s.message, s.hardware_id, s.level))
00243 self._has_warned_no_name = True
00244
00245 if not s.name:
00246 continue
00247
00248 if (len(s.name) > 0 and s.name[0] != '/'):
00249 s.name = '/' + s.name
00250
00251 if (s.name not in self._items):
00252 i = StatusItem(s)
00253 added.append(i)
00254 items[s.name] = i
00255 else:
00256 i = self._items[s.name]
00257 i.update(s)
00258 items[s.name] = i
00259
00260
00261
00262 to_add = []
00263 dummy_names = []
00264 for i in items.itervalues():
00265 parent = i.status.name
00266 while (len(parent) != 0):
00267 parent = get_parent_name(parent)
00268 if (len(parent) > 0 and
00269 (parent not in items) and
00270 parent not in dummy_names):
00271
00272 pi = None
00273 if (parent not in self._items):
00274 s = DiagnosticStatus()
00275 s.name = parent
00276 s.message = ""
00277 pi = StatusItem(s)
00278 else:
00279 pi = self._items[parent]
00280
00281 to_add.append(pi)
00282 dummy_names.append(pi.status.name)
00283
00284 for a in to_add:
00285 if (a.status.name not in items):
00286 items[a.status.name] = a
00287
00288 if (a.status.name not in self._items):
00289 added.append(a)
00290
00291 for i in self._items.itervalues():
00292
00293 if (i.status.name not in items):
00294 removed.append(i)
00295
00296
00297 for r in removed:
00298 del self._items[r.status.name]
00299
00300 self._items = items
00301 self._msg = msg
00302
00303
00304 added.sort(cmp=lambda l,r: cmp(l.status.name, r.status.name))
00305
00306 removed.sort(cmp=lambda l,
00307 r: cmp(l.status.name, r.status.name),
00308 reverse=True)
00309
00310
00311
00312
00313
00314
00315 return (added, removed, self._items)
00316