33 from __future__ 
import division
    34 from __future__ 
import print_function
    41 from python_qt_binding 
import loadUi
    42 from python_qt_binding.QtCore 
import QFile, QIODevice, Qt, Signal, Slot, QAbstractListModel
    43 from python_qt_binding.QtGui 
import QIcon, QImage, QPainter
    44 from python_qt_binding.QtWidgets 
import QFileDialog, QGraphicsScene, QWidget, QCompleter
    45 from python_qt_binding.QtSvg 
import QSvgGenerator
    50 from .dotcode_pack 
import RosPackageGraphDotcodeGenerator
    62     """A completer that completes multiple times from a list"""    65         path = QCompleter.pathFromIndex(self, index)
    66         lst = str(self.widget().text()).split(
',')
    68             path = 
'%s, %s' % (
','.join(lst[:-1]), path)
    72         path = str(path.split(
',')[-1]).lstrip(
' ')
    78     """Ros package and stacknames"""    80     def __init__(self, linewidget, rospack, rosstack):
    81         super(StackageCompletionModel, self).
__init__(linewidget)
    82         self.
allnames = sorted(list(set(rospack.list() + rosstack.list())))
    88     def data(self, index, role):
    90         if index.isValid() 
and (role == Qt.DisplayRole 
or role == Qt.EditRole):
    97     _deferred_fit_in_view = Signal()
   100         super(RosPackGraph, self).
__init__(context)
   109         self.setObjectName(
'RosPackGraph')
   111         rospack = rospkg.RosPack()
   112         rosstack = rospkg.RosStack()
   123         rp = rospkg.RosPack()
   124         ui_file = os.path.join(rp.get_path(
'rqt_dep'), 
'resource', 
'RosPackGraph.ui')
   125         loadUi(ui_file, self.
_widget, {
'InteractiveGraphicsView': InteractiveGraphicsView})
   126         self._widget.setObjectName(
'RosPackGraphUi')
   127         if context.serial_number() > 1:
   128             self._widget.setWindowTitle(
   129                 self._widget.windowTitle() + (
' (%d)' % context.serial_number()))
   132         self._scene.setBackgroundBrush(Qt.white)
   133         self._widget.graphics_view.setScene(self.
_scene)
   135         self._widget.depth_combo_box.insertItem(0, self.tr(
'infinite'), -1)
   136         self._widget.depth_combo_box.insertItem(1, self.tr(
'1'), 2)
   137         self._widget.depth_combo_box.insertItem(2, self.tr(
'2'), 3)
   138         self._widget.depth_combo_box.insertItem(3, self.tr(
'3'), 4)
   139         self._widget.depth_combo_box.insertItem(4, self.tr(
'4'), 5)
   142         self._widget.directions_combo_box.insertItem(0, self.tr(
'depends'), 0)
   143         self._widget.directions_combo_box.insertItem(1, self.tr(
'depends_on'), 1)
   144         self._widget.directions_combo_box.insertItem(2, self.tr(
'both'), 2)
   147         self._widget.package_type_combo_box.insertItem(0, self.tr(
'wet & dry'), 3)
   148         self._widget.package_type_combo_box.insertItem(1, self.tr(
'wet only'), 2)
   149         self._widget.package_type_combo_box.insertItem(2, self.tr(
'dry only'), 1)
   154         completer.setCompletionMode(QCompleter.PopupCompletion)
   155         completer.setWrapAround(
True)
   157         completer.setCaseSensitivity(Qt.CaseInsensitive)
   159         self._widget.filter_line_edit.setCompleter(completer)
   160         self._widget.filter_line_edit.selectionChanged.connect(self.
_clear_filter)
   168         self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme(
'view-refresh'))
   173         self._widget.fit_in_view_push_button.setIcon(QIcon.fromTheme(
'zoom-original'))
   174         self._widget.fit_in_view_push_button.pressed.connect(self.
_fit_in_view)
   176         self._widget.load_dot_push_button.setIcon(QIcon.fromTheme(
'document-open'))
   177         self._widget.load_dot_push_button.pressed.connect(self.
_load_dot)
   178         self._widget.save_dot_push_button.setIcon(QIcon.fromTheme(
'document-save-as'))
   179         self._widget.save_dot_push_button.pressed.connect(self.
_save_dot)
   180         self._widget.save_as_svg_push_button.setIcon(QIcon.fromTheme(
'document-save-as'))
   181         self._widget.save_as_svg_push_button.pressed.connect(self.
_save_svg)
   182         self._widget.save_as_image_push_button.setIcon(QIcon.fromTheme(
'image'))
   183         self._widget.save_as_image_push_button.pressed.connect(self.
_save_image)
   185         self._deferred_fit_in_view.connect(self.
_fit_in_view, Qt.QueuedConnection)
   186         self._deferred_fit_in_view.emit()
   188         context.add_widget(self.
_widget)
   196         self._update_thread.kill()
   199         instance_settings.set_value(
   200             'depth_combo_box_index', self._widget.depth_combo_box.currentIndex())
   201         instance_settings.set_value(
   202             'directions_combo_box_index', self._widget.directions_combo_box.currentIndex())
   203         instance_settings.set_value(
   204             'package_type_combo_box', self._widget.package_type_combo_box.currentIndex())
   205         instance_settings.set_value(
'filter_line_edit_text', self._widget.filter_line_edit.text())
   206         instance_settings.set_value(
   207             'with_stacks_state', self._widget.with_stacks_check_box.isChecked())
   208         instance_settings.set_value(
   209             'hide_transitives_state', self._widget.hide_transitives_check_box.isChecked())
   210         instance_settings.set_value(
   211             'show_system_state', self._widget.show_system_check_box.isChecked())
   212         instance_settings.set_value(
'mark_state', self._widget.mark_check_box.isChecked())
   213         instance_settings.set_value(
'colorize_state', self._widget.colorize_check_box.isChecked())
   214         instance_settings.set_value(
   215             'auto_fit_graph_check_box_state', self._widget.auto_fit_graph_check_box.isChecked())
   216         instance_settings.set_value(
'highlight_connections_check_box_state',
   217                                     self._widget.highlight_connections_check_box.isChecked())
   220         _str_filter = instance_settings.value(
'filter_line_edit_text', 
'')
   221         if (_str_filter == 
None or _str_filter == 
'') 
and \
   223             _str_filter = 
'(Separate pkgs by comma)'   227         self._widget.depth_combo_box.setCurrentIndex(
   228             int(instance_settings.value(
'depth_combo_box_index', 0)))
   229         self._widget.directions_combo_box.setCurrentIndex(
   230             int(instance_settings.value(
'directions_combo_box_index', 0)))
   231         self._widget.package_type_combo_box.setCurrentIndex(
   232             int(instance_settings.value(
'package_type_combo_box', 0)))
   233         self._widget.filter_line_edit.setText(_str_filter)
   234         self._widget.with_stacks_check_box.setChecked(
   235             instance_settings.value(
'with_stacks_state', 
True) 
in [
True, 
'true'])
   236         self._widget.mark_check_box.setChecked(
   237             instance_settings.value(
'mark_state', 
True) 
in [
True, 
'true'])
   238         self._widget.colorize_check_box.setChecked(
   239             instance_settings.value(
'colorize_state', 
False) 
in [
True, 
'true'])
   240         self._widget.hide_transitives_check_box.setChecked(
   241             instance_settings.value(
'hide_transitives_state', 
False) 
in [
True, 
'true'])
   242         self._widget.show_system_check_box.setChecked(
   243             instance_settings.value(
'show_system_state', 
False) 
in [
True, 
'true'])
   244         self._widget.auto_fit_graph_check_box.setChecked(instance_settings.value(
   245             'auto_fit_graph_check_box_state', 
True) 
in [
True, 
'true'])
   246         self._widget.highlight_connections_check_box.setChecked(instance_settings.value(
   247             'highlight_connections_check_box_state', 
True) 
in [
True, 
'true'])
   253         self._widget.depth_combo_box.setEnabled(
True)
   254         self._widget.directions_combo_box.setEnabled(
True)
   255         self._widget.package_type_combo_box.setEnabled(
True)
   256         self._widget.filter_line_edit.setEnabled(
True)
   257         self._widget.with_stacks_check_box.setEnabled(
True)
   258         self._widget.mark_check_box.setEnabled(
True)
   259         self._widget.colorize_check_box.setEnabled(
True)
   260         self._widget.hide_transitives_check_box.setEnabled(
True)
   261         self._widget.show_system_check_box.setEnabled(
True)
   266         self.
_options[
'depth'] = self._widget.depth_combo_box.itemData(
   267             self._widget.depth_combo_box.currentIndex())
   268         self.
_options[
'directions'] = self._widget.directions_combo_box.itemData(
   269             self._widget.directions_combo_box.currentIndex())
   270         self.
_options[
'package_types'] = self._widget.package_type_combo_box.itemData(
   271             self._widget.package_type_combo_box.currentIndex())
   272         self.
_options[
'with_stacks'] = self._widget.with_stacks_check_box.isChecked()
   273         self.
_options[
'mark_selected'] = self._widget.mark_check_box.isChecked()
   274         self.
_options[
'hide_transitives'] = self._widget.hide_transitives_check_box.isChecked()
   275         self.
_options[
'show_system'] = self._widget.show_system_check_box.isChecked()
   277         self.
_options[
'colortheme'] = 
True if self._widget.colorize_check_box.isChecked() 
else None   278         self.
_options[
'names'] = self._widget.filter_line_edit.text().split(
',')
   279         if self.
_options[
'names'] == [
u'None']:
   281         self.
_options[
'highlight_level'] = \
   282             3 
if self._widget.highlight_connections_check_box.isChecked() 
else 1
   283         self.
_options[
'auto_fit'] = self._widget.auto_fit_graph_check_box.isChecked()
   289         self._update_thread.kill()
   294         new_options_serialized = pickle.dumps(self.
_options)
   299         self._scene.setBackgroundBrush(Qt.lightGray)
   301         self._update_thread.start()
   307         except Exception 
as e:
   308             print(str(type(e)), str(e), file=sys.stderr)
   314         self._scene.setBackgroundBrush(Qt.white)
   322             if name.strip().startswith(
'-'):
   323                 excludes.append(name.strip()[1:])
   325                 includes.append(name.strip())
   329         if self.
_options[
'directions'] == 1:
   331         if self.
_options[
'directions'] == 0:
   333         return self.dotcode_generator.generate_dotcode(
   335             selected_names=includes,
   338             with_stacks=self.
_options[
'with_stacks'],
   339             descendants=descendants,
   341             mark_selected=self.
_options[
'mark_selected'],
   342             colortheme=self.
_options[
'colortheme'],
   343             hide_transitives=self.
_options[
'hide_transitives'],
   344             show_system=self.
_options[
'show_system'],
   345             hide_wet=self.
_options[
'package_types'] == 1,
   346             hide_dry=self.
_options[
'package_types'] == 2)
   351         self.
_nodes, self.
_edges = self.dot_to_qt.dotcode_to_qt_items(
   355         if url 
is not None and ':' in url:
   356             item_type, item_path = url.split(
':', 1)
   357             if item_type == 
'node':
   358                 tool_tip = 
'Node:\n  %s' % (item_path)
   359                 service_names = rosservice.get_service_list(node=item_path)
   361                     tool_tip += 
'\nServices:'   362                     for service_name 
in service_names:
   364                             service_type = rosservice.get_service_type(service_name)
   365                             tool_tip += 
'\n  %s [%s]' % (service_name, service_type)
   366                         except rosservice.ROSServiceIOException 
as e:
   367                             tool_tip += 
'\n  %s' % (e)
   369             elif item_type == 
'topic':
   370                 topic_type, topic_name, _ = rostopic.get_topic_type(item_path)
   371                 return 'Topic:\n  %s\nType:\n  %s' % (topic_name, topic_type)
   376         for item 
in self._scene.items():
   377             self._scene.removeItem(item)
   379         for node_item 
in self._nodes.values():
   380             self._scene.addItem(node_item)
   381         for edge_items 
in self._edges.values():
   382             for edge_item 
in edge_items:
   383                 edge_item.add_to_scene(self.
_scene)
   385         self._scene.setSceneRect(self._scene.itemsBoundingRect())
   390         if file_name 
is None:
   391             file_name, _ = QFileDialog.getOpenFileName(
   392                 self.
_widget, self.tr(
'Open graph from file'), 
None, self.tr(
'DOT graph (*.dot)'))
   393             if file_name 
is None or file_name == 
'':
   397             fh = open(file_name, 
'rb')
   404         self._widget.depth_combo_box.setEnabled(
False)
   405         self._widget.directions_combo_box.setEnabled(
False)
   406         self._widget.package_type_combo_box.setEnabled(
False)
   407         self._widget.filter_line_edit.setEnabled(
False)
   408         self._widget.with_stacks_check_box.setEnabled(
False)
   409         self._widget.mark_check_box.setEnabled(
False)
   410         self._widget.colorize_check_box.setEnabled(
False)
   411         self._widget.hide_transitives_check_box.setEnabled(
False)
   412         self._widget.show_system_check_box.setEnabled(
False)
   419         self._widget.graphics_view.fitInView(self._scene.itemsBoundingRect(), Qt.KeepAspectRatio)
   422         file_name, _ = QFileDialog.getSaveFileName(
   423             self.
_widget, self.tr(
'Save as DOT'), 
'rospackgraph.dot', self.tr(
'DOT graph (*.dot)'))
   424         if file_name 
is None or file_name == 
'':
   427         handle = QFile(file_name)
   428         if not handle.open(QIODevice.WriteOnly | QIODevice.Text):
   435         file_name, _ = QFileDialog.getSaveFileName(
   437             self.tr(
'Save as SVG'),
   439             self.tr(
'Scalable Vector Graphic (*.svg)'))
   440         if file_name 
is None or file_name == 
'':
   443         generator = QSvgGenerator()
   444         generator.setFileName(file_name)
   445         generator.setSize((self._scene.sceneRect().size() * 2.0).toSize())
   447         painter = QPainter(generator)
   448         painter.setRenderHint(QPainter.Antialiasing)
   449         self._scene.render(painter)
   453         file_name, _ = QFileDialog.getSaveFileName(
   455             self.tr(
'Save as image'),
   457             self.tr(
'Image (*.bmp *.jpg *.png *.tiff)'))
   458         if file_name 
is None or file_name == 
'':
   462             (self._scene.sceneRect().size() * 2.0).toSize(),
   463             QImage.Format_ARGB32_Premultiplied)
   464         painter = QPainter(img)
   465         painter.setRenderHint(QPainter.Antialiasing)
   466         self._scene.render(painter)
   472             self._widget.filter_line_edit.setText(
'')
 def shutdown_plugin(self)
 
def save_settings(self, plugin_settings, instance_settings)
 
def __init__(self, linewidget, rospack, rosstack)
 
def _update_rospackgraph(self)
 
def pathFromIndex(self, index)
 
def _refresh_rospackgraph(self, force_update=False)
 
def _generate_tool_tip(self, url)
 
def _update_options(self)
 
def splitPath(self, path)
 
def data(self, index, role)
 
def __init__(self, context)
 
def _load_dot(self, file_name=None)
 
def rowCount(self, parent)
 
def _update_finished(self)
 
def _generate_dotcode(self)
 
def restore_settings(self, plugin_settings, instance_settings)
 
def _redraw_graph_scene(self)
 
def _update_thread_run(self)
 
def _update_graph(self, dotcode)