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