31 from __future__ 
import division
    35 from python_qt_binding 
import loadUi
    36 from python_qt_binding.QtCore 
import QAbstractListModel, QFile, QIODevice, Qt, Signal
    37 from python_qt_binding.QtGui 
import QIcon, QImage, QPainter
    38 from python_qt_binding.QtWidgets 
import QCompleter, QFileDialog, QGraphicsScene, QWidget
    39 from python_qt_binding.QtSvg 
import QSvgGenerator
    41 import rosgraph.impl.graph
    52 from .dotcode 
import RosGraphDotcodeGenerator, NODE_NODE_GRAPH, NODE_TOPIC_ALL_GRAPH, NODE_TOPIC_GRAPH
    53 from .interactive_graphics_view 
import InteractiveGraphicsView
    65     """A completer that completes multiple times from a list"""    67     def init(self, parent=None):
    68         QCompleter.init(self, parent)
    71         path = QCompleter.pathFromIndex(self, index)
    72         lst = 
unicode(self.widget().text()).split(
',')
    74             path = 
'%s, %s' % (
','.join(lst[:-1]), path)
    78         path = 
unicode(path.split(
',')[-1]).lstrip(
' ')
    84     """Ros package and stacknames"""    87         super(NamespaceCompletionModel, self).
__init__(linewidget)
    93             namesset.add(
unicode(n).strip())
    94             namesset.add(
"-%s" % (
unicode(n).strip()))
    95         self.
names = sorted(namesset)
    98         return len(self.
names)
   101         if index.isValid() 
and (role == Qt.DisplayRole 
or role == Qt.EditRole):
   102             return self.
names[index.row()]
   108     _deferred_fit_in_view = Signal()
   111         super(RosGraph, self).
__init__(context)
   113         self.setObjectName(
'RosGraph')
   128         rp = rospkg.RosPack()
   129         ui_file = os.path.join(rp.get_path(
'rqt_graph'), 
'resource', 
'RosGraph.ui')
   130         loadUi(ui_file, self.
_widget, {
'InteractiveGraphicsView': InteractiveGraphicsView})
   131         self.
_widget.setObjectName(
'RosGraphUi')
   132         if context.serial_number() > 1:
   134                 self.
_widget.windowTitle() + (
' (%d)' % context.serial_number()))
   137         self.
_scene.setBackgroundBrush(Qt.white)
   140         self.
_widget.graph_type_combo_box.insertItem(0, self.tr(
'Nodes only'), NODE_NODE_GRAPH)
   141         self.
_widget.graph_type_combo_box.insertItem(
   142             1, self.tr(
'Nodes/Topics (active)'), NODE_TOPIC_GRAPH)
   143         self.
_widget.graph_type_combo_box.insertItem(
   144             2, self.tr(
'Nodes/Topics (all)'), NODE_TOPIC_ALL_GRAPH)
   145         self.
_widget.graph_type_combo_box.setCurrentIndex(0)
   150         completer.setCompletionMode(QCompleter.PopupCompletion)
   151         completer.setWrapAround(
True)
   152         completer.setCaseSensitivity(Qt.CaseInsensitive)
   154         self.
_widget.filter_line_edit.setCompleter(completer)
   157             self.
_widget.topic_filter_line_edit, 
False)
   159         topic_completer.setCompletionMode(QCompleter.PopupCompletion)
   160         topic_completer.setWrapAround(
True)
   161         topic_completer.setCaseSensitivity(Qt.CaseInsensitive)
   163         self.
_widget.topic_filter_line_edit.setCompleter(topic_completer)
   175         self.
_widget.refresh_graph_push_button.setIcon(QIcon.fromTheme(
'view-refresh'))
   180         self.
_widget.fit_in_view_push_button.setIcon(QIcon.fromTheme(
'zoom-original'))
   183         self.
_widget.load_dot_push_button.setIcon(QIcon.fromTheme(
'document-open'))
   185         self.
_widget.save_dot_push_button.setIcon(QIcon.fromTheme(
'document-save-as'))
   187         self.
_widget.save_as_svg_push_button.setIcon(QIcon.fromTheme(
'document-save-as'))
   189         self.
_widget.save_as_image_push_button.setIcon(QIcon.fromTheme(
'image'))
   196         context.add_widget(self.
_widget)
   199         instance_settings.set_value(
   200             'graph_type_combo_box_index', self.
_widget.graph_type_combo_box.currentIndex())
   201         instance_settings.set_value(
'filter_line_edit_text', self.
_widget.filter_line_edit.text())
   202         instance_settings.set_value(
   203             'topic_filter_line_edit_text', self.
_widget.topic_filter_line_edit.text())
   204         instance_settings.set_value(
   205             'namespace_cluster_spin_box_value', self.
_widget.namespace_cluster_spin_box.value())
   206         instance_settings.set_value(
   207             'actionlib_check_box_state', self.
_widget.actionlib_check_box.isChecked())
   208         instance_settings.set_value(
   209             'dead_sinks_check_box_state', self.
_widget.dead_sinks_check_box.isChecked())
   210         instance_settings.set_value(
   211             'leaf_topics_check_box_state', self.
_widget.leaf_topics_check_box.isChecked())
   212         instance_settings.set_value(
   213             'quiet_check_box_state', self.
_widget.quiet_check_box.isChecked())
   214         instance_settings.set_value(
   215             'unreachable_check_box_state', self.
_widget.unreachable_check_box.isChecked())
   216         instance_settings.set_value(
   217             'auto_fit_graph_check_box_state', self.
_widget.auto_fit_graph_check_box.isChecked())
   218         instance_settings.set_value(
   219             'highlight_connections_check_box_state', self.
_widget.highlight_connections_check_box.isChecked())
   220         instance_settings.set_value(
   221             'group_tf_check_box_state', self.
_widget.group_tf_check_box.isChecked())
   222         instance_settings.set_value(
   223             'hide_tf_nodes_check_box_state', self.
_widget.hide_tf_nodes_check_box.isChecked())
   224         instance_settings.set_value(
   225             'group_image_check_box_state', self.
_widget.group_image_check_box.isChecked())
   226         instance_settings.set_value(
   227             'hide_dynamic_reconfigure_check_box_state', self.
_widget.hide_dynamic_reconfigure_check_box.isChecked())
   230         self.
_widget.graph_type_combo_box.setCurrentIndex(
   231             int(instance_settings.value(
'graph_type_combo_box_index', 0)))
   232         self.
_widget.filter_line_edit.setText(instance_settings.value(
'filter_line_edit_text', 
'/'))
   233         self.
_widget.topic_filter_line_edit.setText(
   234             instance_settings.value(
'topic_filter_line_edit_text', 
'/'))
   235         self.
_widget.namespace_cluster_spin_box.setValue(
   236             int(instance_settings.value(
'namespace_cluster_spin_box_value', 2)))
   237         self.
_widget.actionlib_check_box.setChecked(
   238             instance_settings.value(
'actionlib_check_box_state', 
True) 
in [
True, 
'true'])
   239         self.
_widget.dead_sinks_check_box.setChecked(
   240             instance_settings.value(
'dead_sinks_check_box_state', 
True) 
in [
True, 
'true'])
   241         self.
_widget.leaf_topics_check_box.setChecked(
   242             instance_settings.value(
'leaf_topics_check_box_state', 
True) 
in [
True, 
'true'])
   243         self.
_widget.quiet_check_box.setChecked(
   244             instance_settings.value(
'quiet_check_box_state', 
True) 
in [
True, 
'true'])
   245         self.
_widget.unreachable_check_box.setChecked(
   246             instance_settings.value(
'unreachable_check_box_state', 
True) 
in [
True, 
'true'])
   247         self.
_widget.auto_fit_graph_check_box.setChecked(
   248             instance_settings.value(
'auto_fit_graph_check_box_state', 
True) 
in [
True, 
'true'])
   249         self.
_widget.highlight_connections_check_box.setChecked(
   250             instance_settings.value(
'highlight_connections_check_box_state', 
True) 
in [
True, 
'true'])
   251         self.
_widget.hide_tf_nodes_check_box.setChecked(
   252             instance_settings.value(
'hide_tf_nodes_check_box_state', 
False) 
in [
True, 
'true'])
   253         self.
_widget.group_tf_check_box.setChecked(
   254             instance_settings.value(
'group_tf_check_box_state', 
True) 
in [
True, 
'true'])
   255         self.
_widget.group_image_check_box.setChecked(
   256             instance_settings.value(
'group_image_check_box_state', 
True) 
in [
True, 
'true'])
   257         self.
_widget.hide_dynamic_reconfigure_check_box.setChecked(
   258             instance_settings.value(
'hide_dynamic_reconfigure_check_box_state', 
True) 
in [
True, 
'true'])
   264         self.
_widget.graph_type_combo_box.setEnabled(
True)
   265         self.
_widget.filter_line_edit.setEnabled(
True)
   266         self.
_widget.topic_filter_line_edit.setEnabled(
True)
   267         self.
_widget.namespace_cluster_spin_box.setEnabled(
True)
   268         self.
_widget.actionlib_check_box.setEnabled(
True)
   269         self.
_widget.dead_sinks_check_box.setEnabled(
True)
   270         self.
_widget.leaf_topics_check_box.setEnabled(
True)
   271         self.
_widget.quiet_check_box.setEnabled(
True)
   272         self.
_widget.unreachable_check_box.setEnabled(
True)
   273         self.
_widget.group_tf_check_box.setEnabled(
True)
   274         self.
_widget.hide_tf_nodes_check_box.setEnabled(
True)
   275         self.
_widget.group_image_check_box.setEnabled(
True)
   276         self.
_widget.hide_dynamic_reconfigure_check_box.setEnabled(
True)
   278         self.
_graph = rosgraph.impl.graph.Graph()
   279         self.
_graph.set_master_stale(5.0)
   280         self.
_graph.set_node_stale(5.0)
   292         ns_filter = self.
_widget.filter_line_edit.text()
   293         topic_filter = self.
_widget.topic_filter_line_edit.text()
   294         graph_mode = self.
_widget.graph_type_combo_box.itemData(
   295             self.
_widget.graph_type_combo_box.currentIndex())
   297         namespace_cluster = self.
_widget.namespace_cluster_spin_box.value()
   298         accumulate_actions = self.
_widget.actionlib_check_box.isChecked()
   299         hide_dead_end_topics = self.
_widget.dead_sinks_check_box.isChecked()
   300         hide_single_connection_topics = self.
_widget.leaf_topics_check_box.isChecked()
   301         quiet = self.
_widget.quiet_check_box.isChecked()
   302         unreachable = self.
_widget.unreachable_check_box.isChecked()
   303         group_tf_nodes = self.
_widget.group_tf_check_box.isChecked()
   304         hide_tf_nodes = self.
_widget.hide_tf_nodes_check_box.isChecked()
   305         group_image_nodes = self.
_widget.group_image_check_box.isChecked()
   306         hide_dynamic_reconfigure = self.
_widget.hide_dynamic_reconfigure_check_box.isChecked()
   311             topic_filter=topic_filter,
   312             graph_mode=graph_mode,
   313             hide_single_connection_topics=hide_single_connection_topics,
   314             hide_dead_end_topics=hide_dead_end_topics,
   315             cluster_namespaces_level=namespace_cluster,
   316             accumulate_actions=accumulate_actions,
   318             orientation=orientation,
   320             unreachable=unreachable,
   321             group_tf_nodes=group_tf_nodes,
   322             hide_tf_nodes=hide_tf_nodes,
   323             group_image_nodes=group_image_nodes,
   324             hide_dynamic_reconfigure=hide_dynamic_reconfigure)
   333         if url 
is not None and ':' in url:
   334             item_type, item_path = url.split(
':', 1)
   335             if item_type == 
'node':
   336                 tool_tip = 
'Node:\n  %s' % (item_path)
   337                 service_names = rosservice.get_service_list(node=item_path)
   339                     tool_tip += 
'\nServices:'   340                     for service_name 
in service_names:
   342                             service_type = rosservice.get_service_type(service_name)
   343                             tool_tip += 
'\n  %s [%s]' % (service_name, service_type)
   344                         except rosservice.ROSServiceIOException 
as e:
   345                             tool_tip += 
'\n  %s' % (e)
   347             elif item_type == 
'topic':
   348                 topic_type, topic_name, _ = rostopic.get_topic_type(item_path)
   349                 return 'Topic:\n  %s\nType:\n  %s' % (topic_name, topic_type)
   355         if self.
_widget.highlight_connections_check_box.isChecked():
   362                                                             highlight_level=highlight_level,
   363                                                             same_label_siblings=
True,
   366         self.
_scene.setSceneRect(self.
_scene.itemsBoundingRect())
   367         if self.
_widget.auto_fit_graph_check_box.isChecked():
   371         if file_name 
is None:
   372             file_name, _ = QFileDialog.getOpenFileName(
   373                 self.
_widget, self.tr(
'Open graph from file'), 
None, self.tr(
'DOT graph (*.dot)'))
   374             if file_name 
is None or file_name == 
'':
   378             fh = open(file_name, 
'rb')
   385         self.
_widget.graph_type_combo_box.setEnabled(
False)
   386         self.
_widget.filter_line_edit.setEnabled(
False)
   387         self.
_widget.topic_filter_line_edit.setEnabled(
False)
   388         self.
_widget.namespace_cluster_spin_box.setEnabled(
False)
   389         self.
_widget.actionlib_check_box.setEnabled(
False)
   390         self.
_widget.dead_sinks_check_box.setEnabled(
False)
   391         self.
_widget.leaf_topics_check_box.setEnabled(
False)
   392         self.
_widget.quiet_check_box.setEnabled(
False)
   393         self.
_widget.unreachable_check_box.setEnabled(
False)
   394         self.
_widget.group_tf_check_box.setEnabled(
False)
   395         self.
_widget.hide_tf_nodes_check_box.setEnabled(
False)
   396         self.
_widget.group_image_check_box.setEnabled(
False)
   397         self.
_widget.hide_dynamic_reconfigure_check_box.setEnabled(
False)
   402         self.
_widget.graphics_view.fitInView(self.
_scene.itemsBoundingRect(), Qt.KeepAspectRatio)
   405         file_name, _ = QFileDialog.getSaveFileName(
   406             self.
_widget, self.tr(
'Save as DOT'), 
'rosgraph.dot', self.tr(
'DOT graph (*.dot)'))
   407         if file_name 
is None or file_name == 
'':
   410         handle = QFile(file_name)
   411         if not handle.open(QIODevice.WriteOnly | QIODevice.Text):
   418         file_name, _ = QFileDialog.getSaveFileName(
   419             self.
_widget, self.tr(
'Save as SVG'), 
'rosgraph.svg', self.tr(
'Scalable Vector Graphic (*.svg)'))
   420         if file_name 
is None or file_name == 
'':
   423         generator = QSvgGenerator()
   424         generator.setFileName(file_name)
   425         generator.setSize((self.
_scene.sceneRect().size() * 2.0).toSize())
   427         painter = QPainter(generator)
   428         painter.setRenderHint(QPainter.Antialiasing)
   429         self.
_scene.render(painter)
   433         file_name, _ = QFileDialog.getSaveFileName(
   434             self.
_widget, self.tr(
'Save as image'), 
'rosgraph.png', self.tr(
'Image (*.bmp *.jpg *.png *.tiff)'))
   435         if file_name 
is None or file_name == 
'':
   438         img = QImage((self.
_scene.sceneRect().size() * 2.0)
   439                      .toSize(), QImage.Format_ARGB32_Premultiplied)
   440         painter = QPainter(img)
   441         painter.setRenderHint(QPainter.Antialiasing)
   442         self.
_scene.render(painter)
 def _redraw_graph_view(self)
 
def __init__(self, linewidget, topics_only)
 
def restore_settings(self, plugin_settings, instance_settings)
 
def __init__(self, context)
 
def splitPath(self, path)
 
def _generate_dotcode(self)
 
def save_settings(self, plugin_settings, instance_settings)
 
def data(self, index, role)
 
def _generate_tool_tip(self, url)
 
def init(self, parent=None)
 
def pathFromIndex(self, index)
 
def _refresh_rosgraph(self)
 
def _load_dot(self, file_name=None)
 
def rowCount(self, parent)
 
def _update_graph_view(self, dotcode)
 
def _update_rosgraph(self)