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 from __future__ import division
00030 import roslib; roslib.load_manifest('rostop_gui')
00031
00032 from qt_gui.plugin import Plugin
00033 from python_qt_binding import loadUi
00034 from python_qt_binding.QtGui import QLabel, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QCheckBox, QWidget, QToolBar, QLineEdit, QPushButton
00035 from python_qt_binding.QtCore import Qt, QTimer
00036
00037 from rostop_gui.node_info import NodeInfo
00038 import re
00039 from threading import RLock
00040 import textwrap
00041
00042 class RosTop(Plugin):
00043
00044 node_fields = [ 'pid', 'get_cpu_percent', 'get_memory_percent', 'get_num_threads']
00045 out_fields = ['node_name', 'pid', 'cpu_percent', 'memory_percent', 'num_threads' ]
00046 format_strs = ['%s', '%s', '%0.2f', '%0.2f', '%s' ]
00047 node_labels = ['Node', 'PID', 'CPU %', 'Mem %', 'Num Threads' ]
00048 tooltips = {
00049 0: ('cmdline', lambda x: '\n'.join(textwrap.wrap(' '.join(x)))),
00050 3: ('memory_info', lambda x: ('Resident: %0.2f MiB, Virtual: %0.2f MiB' % (x[0]/2**20, x[1]/2**20)))
00051 }
00052
00053 _node_info = NodeInfo()
00054
00055 name_filter = re.compile('')
00056
00057 def __init__(self, context):
00058 super(RosTop, self).__init__(context)
00059
00060 self.setObjectName('RosTop')
00061
00062
00063 from argparse import ArgumentParser
00064 parser = ArgumentParser()
00065
00066 parser.add_argument("-q", "--quiet", action="store_true",
00067 dest="quiet",
00068 help="Put plugin in silent mode")
00069 args, unknowns = parser.parse_known_args(context.argv())
00070
00071
00072
00073
00074 self._selected_node = ''
00075 self._selected_node_lock = RLock()
00076
00077
00078 self._toolbar = QToolBar()
00079 self._filter_box = QLineEdit()
00080 self._regex_box = QCheckBox()
00081 self._regex_box.setText('regex')
00082 self._toolbar.addWidget(QLabel('Filter'))
00083 self._toolbar.addWidget(self._filter_box)
00084 self._toolbar.addWidget(self._regex_box)
00085
00086 self._filter_box.returnPressed.connect(self.update_filter)
00087 self._regex_box.stateChanged.connect(self.update_filter)
00088
00089
00090 self._container = QWidget()
00091 self._layout = QVBoxLayout()
00092 self._container.setLayout(self._layout)
00093
00094 self._layout.addWidget(self._toolbar)
00095
00096
00097 self._table_widget = QTreeWidget()
00098 self._table_widget.setObjectName('TopTable')
00099 self._table_widget.setColumnCount(len(self.node_labels))
00100 self._table_widget.setHeaderLabels(self.node_labels)
00101 self._table_widget.itemClicked.connect(self._tableItemClicked)
00102 self._table_widget.setSortingEnabled(True)
00103 self._table_widget.setAlternatingRowColors(True)
00104
00105 self._layout.addWidget(self._table_widget)
00106 context.add_widget(self._container)
00107
00108
00109 self._kill_button = QPushButton('Kill Node')
00110 self._layout.addWidget(self._kill_button)
00111 self._kill_button.clicked.connect(self._kill_node)
00112
00113
00114 self.update_table()
00115 self.update_table()
00116
00117 self._table_widget.resizeColumnToContents(0)
00118
00119
00120 self._update_timer = QTimer()
00121 self._update_timer.setInterval(1000)
00122 self._update_timer.timeout.connect(self.update_table)
00123 self._update_timer.start()
00124
00125 def _tableItemClicked(self, item, column):
00126 with self._selected_node_lock:
00127 self._selected_node = item.text(0)
00128
00129 def update_filter(self, *args):
00130 if self._regex_box.isChecked():
00131 expr = self._filter_box.text()
00132 else:
00133 expr = re.escape(self._filter_box.text())
00134 self.name_filter = re.compile(expr)
00135 self.update_table()
00136
00137 def _kill_node(self):
00138 self._node_info.kill_node(self._selected_node)
00139
00140 def update_one_item(self, row, info):
00141 twi = QTreeWidgetItem()
00142 for col, field in enumerate(self.out_fields):
00143 val = info[field]
00144 twi.setText(col, self.format_strs[col] % val)
00145 self._table_widget.insertTopLevelItem(row, twi)
00146
00147 for col, (key, func) in self.tooltips.iteritems():
00148 twi.setToolTip(col, func(info[key]))
00149
00150 with self._selected_node_lock:
00151 if twi.text(0) == self._selected_node:
00152 twi.setSelected(True)
00153
00154 self._table_widget.setItemHidden(twi, len(self.name_filter.findall(info['node_name'])) == 0)
00155
00156 def update_table(self):
00157 self._table_widget.clear()
00158 infos = self._node_info.get_all_node_fields(self.node_fields)
00159 for nx, info in enumerate(infos):
00160 self.update_one_item(nx, info)
00161
00162 def shutdown_plugin(self):
00163 self._update_timer.stop()
00164
00165 def save_settings(self, plugin_settings, instance_settings):
00166 instance_settings.set_value('filter_text', self._filter_box.text())
00167 instance_settings.set_value('is_regex', int(self._regex_box.checkState()))
00168
00169 def restore_settings(self, plugin_settings, instance_settings):
00170 self._filter_box.setText(instance_settings.value('filter_text'))
00171 self._regex_box.setCheckState(Qt.CheckState(instance_settings.value('is_regex')))
00172 self.update_filter()
00173
00174
00175
00176