33 from __future__
import division
36 from python_qt_binding
import loadUi
37 from python_qt_binding.QtCore
import Qt, QTimer, Signal, Slot
38 from python_qt_binding.QtGui
import QIcon
39 from python_qt_binding.QtWidgets
import QHeaderView, QMenu, QTreeWidgetItem, QWidget
43 from rospy.exceptions
import ROSException
45 from .topic_info
import TopicInfo
51 main class inherits from the ui window class. 53 You can specify the topics that the topic pane. 55 TopicWidget.start must be called in order to update topic pane. 61 _column_names = [
'topic',
'type',
'bandwidth',
'rate',
'value']
63 def __init__(self, plugin=None, selected_topics=None, select_topic_type=SELECT_BY_NAME):
65 @type selected_topics: list of tuples. 66 @param selected_topics: [($NAME_TOPIC$, $TYPE_TOPIC$), ...] 67 @type select_topic_type: int 68 @param select_topic_type: Can specify either the name of topics or by 69 the type of topic, to filter the topics to 70 show. If 'select_topic_type' argument is 71 None, this arg shouldn't be meaningful. 78 ui_file = os.path.join(rp.get_path(
'rqt_topic'),
'resource',
'TopicWidget.ui')
81 self.topics_tree_widget.sortByColumn(0, Qt.AscendingOrder)
82 header = self.topics_tree_widget.header()
84 setSectionResizeMode = header.setSectionResizeMode
85 except AttributeError:
86 setSectionResizeMode = header.setResizeMode
87 setSectionResizeMode(QHeaderView.ResizeToContents)
88 header.customContextMenuRequested.connect(
90 header.setContextMenuPolicy(Qt.CustomContextMenu)
114 This method needs to be called to start updating topic pane. 116 self._timer_refresh_topics.start(1000)
121 refresh tree view items 125 topic_list = rospy.get_published_topics()
126 if topic_list
is None:
128 'Not even a single published topic found. Check network configuration')
132 topic_specifiers_server_all =
None 133 topic_specifiers_required =
None 135 rospy.logdebug(
'refresh_topics) self._selected_topics=%s' % (topic_list,))
138 topic_specifiers_server_all = \
139 [name
for name, type
in rospy.get_published_topics()]
140 topic_specifiers_required = [name
for name, type
in topic_list]
143 topic_specifiers_required = [type
for name, type
in topic_list]
146 topics_match = [(name, type)
for name, type
in rospy.get_published_topics()
147 if type
in topic_specifiers_required]
148 topic_list = topics_match
149 rospy.logdebug(
'selected & published topic types=%s' % (topic_list,))
151 rospy.logdebug(
'server_all=%s\nrequired=%s\ntlist=%s' %
152 (topic_specifiers_server_all, topic_specifiers_required, topic_list))
153 if len(topic_list) == 0:
155 'None of the following required topics are found.\n(NAME, TYPE): %s' %
159 rospy.logerr(
"Communication with rosmaster failed: {0}".format(e.strerror))
168 for topic_name, topic_type
in topic_list:
170 if topic_name
not in self.
_topics or \
171 self.
_topics[topic_name][
'type'] != topic_type:
173 topic_info = TopicInfo(topic_name, topic_type)
174 message_instance =
None 175 if topic_info.message_class
is not None:
176 message_instance = topic_info.message_class()
179 self.topics_tree_widget, topic_name, topic_type, message_instance)
180 new_topics[topic_name] = {
188 new_topics[topic_name] = self.
_topics[topic_name]
192 for topic_name
in self._topics.keys():
193 self.
_topics[topic_name][
'info'].stop_monitoring()
194 index = self.topics_tree_widget.indexOfTopLevelItem(
195 self.
_topics[topic_name][
'item'])
196 self.topics_tree_widget.takeTopLevelItem(index)
204 for topic
in self._topics.values():
205 topic_info = topic[
'info']
206 if topic_info.monitoring:
208 rate, _, _, _ = topic_info.get_hz()
209 rate_text =
'%1.2f' % rate
if rate !=
None else 'unknown' 212 bytes_per_s, _, _, _ = topic_info.get_bw()
213 if bytes_per_s
is None:
214 bandwidth_text =
'unknown' 215 elif bytes_per_s < 1000:
216 bandwidth_text =
'%.2fB/s' % bytes_per_s
217 elif bytes_per_s < 1000000:
218 bandwidth_text =
'%.2fKB/s' % (bytes_per_s / 1000.)
220 bandwidth_text =
'%.2fMB/s' % (bytes_per_s / 1000000.)
224 self.
update_value(topic_info._topic_name, topic_info.last_message)
230 value_text =
'not monitored' if topic_info.error
is None else topic_info.error
241 if hasattr(message,
'__slots__')
and hasattr(message,
'_slot_types'):
242 for slot_name
in message.__slots__:
243 self.
update_value(topic_name +
'/' + slot_name, getattr(message, slot_name))
245 elif type(message)
in (list, tuple)
and \
246 (len(message) > 0)
and \
247 hasattr(message[0],
'__slots__'):
249 for index, slot
in enumerate(message):
250 if topic_name +
'[%d]' % index
in self.
_tree_items:
257 topic_name +
'[%d]' % index, base_type_str, slot)
259 if len(message) < self.
_tree_items[topic_name].childCount():
260 for i
in range(len(message), self.
_tree_items[topic_name].childCount()):
261 item_topic_name = topic_name +
'[%d]' % i
269 if '[' in type_str
and type_str[-1] ==
']':
270 type_str, array_size_str = type_str.split(
'[', 1)
271 array_size_str = array_size_str[:-1]
272 if len(array_size_str) > 0:
273 array_size = int(array_size_str)
277 return type_str, array_size
280 if parent
is self.topics_tree_widget:
282 topic_text = topic_name
285 topic_text = topic_name.split(
'/')[-1]
286 if '[' in topic_text:
287 topic_text = topic_text[topic_text.index(
'['):]
288 item = QTreeWidgetItem(parent)
291 item.setData(0, Qt.UserRole, topic_name)
293 if hasattr(message,
'__slots__')
and hasattr(message,
'_slot_types'):
294 for slot_name, type_name
in zip(message.__slots__, message._slot_types):
296 item, topic_name +
'/' + slot_name, type_name, getattr(message, slot_name))
301 base_instance = roslib.message.get_message_class(base_type_str)()
302 except (ValueError, TypeError):
304 if array_size
is not None and hasattr(base_instance,
'__slots__'):
305 for index
in range(array_size):
307 item, topic_name +
'[%d]' % index, base_type_str, base_instance)
312 if item.checkState(0):
313 self.
_topics[topic_name][
'info'].start_monitoring()
315 self.
_topics[topic_name][
'info'].stop_monitoring()
318 def _recursive_remove_items_from_tree(item):
319 for index
in reversed(range(item.childCount())):
320 _recursive_remove_items_from_tree(item.child(index))
321 topic_name = item.data(0, Qt.UserRole)
323 _recursive_remove_items_from_tree(item)
324 item.parent().removeChild(item)
328 header = self.topics_tree_widget.header()
332 action_toggle_auto_resize = menu.addAction(
'Toggle Auto-Resize')
333 action = menu.exec_(header.mapToGlobal(pos))
336 if action
is action_toggle_auto_resize:
338 sectionResizeMode = header.sectionResizeMode
339 setSectionResizeMode = header.setSectionResizeMode
340 except AttributeError:
341 sectionResizeMode = header.resizeMode
342 setSectionResizeMode = header.setResizeMode
343 if sectionResizeMode(0) == QHeaderView.ResizeToContents:
344 setSectionResizeMode(QHeaderView.Interactive)
346 setSectionResizeMode(QHeaderView.ResizeToContents)
350 item = self.topics_tree_widget.itemAt(pos)
356 action_item_expand = menu.addAction(QIcon.fromTheme(
'zoom-in'),
'Expand All Children')
357 action_item_collapse = menu.addAction(QIcon.fromTheme(
'zoom-out'),
'Collapse All Children')
358 action = menu.exec_(self.topics_tree_widget.mapToGlobal(pos))
361 if action
in (action_item_expand, action_item_collapse):
362 expanded = (action
is action_item_expand)
364 def recursive_set_expanded(item):
365 item.setExpanded(expanded)
366 for index
in range(item.childCount()):
367 recursive_set_expanded(item.child(index))
368 recursive_set_expanded(item)
371 for topic
in self._topics.values():
372 topic[
'info'].stop_monitoring()
373 self._timer_refresh_topics.stop()
377 @param selected_topics: list of tuple. [(topic_name, topic_type)] 378 @type selected_topics: [] 380 rospy.logdebug(
'set_selected_topics topics={}'.format(len(selected_topics)))
385 header_state = self.topics_tree_widget.header().saveState()
386 instance_settings.set_value(
'tree_widget_header_state', header_state)
389 if instance_settings.contains(
'tree_widget_header_state'):
390 header_state = instance_settings.value(
'tree_widget_header_state')
391 if not self.topics_tree_widget.header().restoreState(header_state):
392 rospy.logwarn(
"rqt_topic: Failed to restore header state.")
397 def __init__(self, check_state_changed_callback, topic_name, parent=None):
398 super(TreeWidgetItem, self).
__init__(parent)
401 self.setCheckState(0, Qt.Unchecked)
404 if role == Qt.CheckStateRole:
405 state = self.checkState(column)
406 super(TreeWidgetItem, self).
setData(column, role, value)
407 if role == Qt.CheckStateRole
and state != self.checkState(column):
411 column = self.treeWidget().sortColumn()
412 if column == TopicWidget._column_names.index(
'bandwidth'):
413 return self.data(column, Qt.UserRole) < other_item.data(column, Qt.UserRole)
414 return super(TreeWidgetItem, self).
__lt__(other_item)