def __init__(self, ros: Ros, parent=None): super(TopicGraphWidget, self).__init__(parent) self.ros_client = ros layout = QVBoxLayout() self._widget = QWidget() self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._graphics_view = InteractiveGraphicsView(self._widget) self._graphics_view.setScene(self._scene) self._graphics_view.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform | QPainter.TextAntialiasing) self._graphics_view.setResizeAnchor(QGraphicsView.AnchorViewCenter) layout.addWidget(self._graphics_view) self._refresh_button = QPushButton('加载数据') self._refresh_button.setFixedWidth(100) self._refresh_button.clicked.connect(self._draw_graph_view) btn_layout = QHBoxLayout() btn_layout.addWidget(self._refresh_button) layout.addLayout(btn_layout) self.setLayout(layout) self._current_dotcode = None self.dot_to_qt = DotToQtGenerator() self.dotcode_factory = PydotFactory() self.dotcode_generator = RosGraphDotcodeGenerator(self.ros_client) self._graph = graph.Graph(self.ros_client) self._graph.set_master_stale(5.0) self._graph.set_node_stale(5.0)
def _render_dotgraph(self, dotgraph): """ Render the specified dotgraph on canvas :type dotgraph: pydot.Dot """ # Only redraw when the graph differs from the previous one if self._prev_dotgraph == dotgraph: return else: self._prev_dotgraph = dotgraph self._scene.clear() if self._widget.highlight_connections_check_box.isChecked(): highlight_level = 3 else: highlight_level = 1 # Generate qt items from dotcode dotcode = PydotFactory().create_dot(dotgraph) nodes, edges = DotToQtGenerator().dotcode_to_qt_items( dotcode, highlight_level, same_label_siblings=False) # Add generated items to scene for node_item in nodes: self._scene.addItem(nodes.get(node_item)) for edge_items in edges: for edge_item in edges.get(edge_items): edge_item.add_to_scene(self._scene) self._scene.setSceneRect(self._scene.itemsBoundingRect())
def test_simple_integration(self): if DotToQtGeneratorTest._Q_APP is None: raise unittest.case.SkipTest (nodes, edges) = DotToQtGenerator().dotcode_to_qt_items( DotToQtGeneratorTest.DOT_CODE, 1) self.assertEqual(3, len(nodes)) # cluster_foo, foo and bar self.assertEqual(1, len(edges)) # foo -> bar
def __init__(self, context): super(RosTfTree, self).__init__(context) self.initialized = False self.setObjectName('RosTfTree') self._current_dotcode = None self._widget = QWidget() # factory builds generic dotcode items self.dotcode_factory = PydotFactory() # self.dotcode_factory = PygraphvizFactory() # generator builds rosgraph self.dotcode_generator = RosTfTreeDotcodeGenerator() self.tf2_buffer_ = tf2_ros.Buffer() self.tf2_listener_ = tf2_ros.TransformListener(self.tf2_buffer_) # dot_to_qt transforms into Qt elements using dot layout self.dot_to_qt = DotToQtGenerator() rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('rqt_tf_tree'), 'resource', 'RosTfTree.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('RosTfTreeUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('view-refresh')) self._widget.refresh_graph_push_button.pressed.connect(self._update_tf_graph) self._widget.highlight_connections_check_box.toggled.connect(self._redraw_graph_view) self._widget.auto_fit_graph_check_box.toggled.connect(self._redraw_graph_view) self._widget.fit_in_view_push_button.setIcon(QIcon.fromTheme('zoom-original')) self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view) self._widget.load_dot_push_button.setIcon(QIcon.fromTheme('document-open')) self._widget.load_dot_push_button.pressed.connect(self._load_dot) self._widget.save_dot_push_button.setIcon(QIcon.fromTheme('document-save-as')) self._widget.save_dot_push_button.pressed.connect(self._save_dot) self._widget.save_as_svg_push_button.setIcon(QIcon.fromTheme('document-save-as')) self._widget.save_as_svg_push_button.pressed.connect(self._save_svg) self._widget.save_as_image_push_button.setIcon(QIcon.fromTheme('image-x-generic')) self._widget.save_as_image_push_button.pressed.connect(self._save_image) self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() context.add_widget(self._widget) self._force_refresh = False
def __init__(self): #Init the base class QtGui.QGraphicsScene.__init__(self) # dot_to_qt transforms into Qt elements using dot layout self._dot_to_qt = DotToQtGenerator() #The pydotfactory self._dot_factory = PydotFactory() self._graph = None pass
def __init__(self, context): self._context=context super(ConductorGraph, self).__init__(context) self.initialised=False self.setObjectName('Conductor Graph') self._current_dotcode=None self._node_items=None self._edge_items=None self._node_item_events={} self._edge_item_events={} self._client_info_list={} self._widget=QWidget() self.cur_selected_client_name = "" self.pre_selected_client_name = "" # factory builds generic dotcode items self.dotcode_factory=PydotFactory() # self.dotcode_factory=PygraphvizFactory() self.dotcode_generator=RosGraphDotcodeGenerator() self.dot_to_qt=DotToQtGenerator() self._graph=ConductorGraphInfo() self._graph._reg_event_callback(self._update_client_list) self._graph._reg_period_callback(self._set_network_statisics) rospack=rospkg.RosPack() ui_file=os.path.join(rospack.get_path('concert_conductor_graph'), 'ui', 'conductor_graph.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('ConductorGraphUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene=QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) #self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('view-refresh')) self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('window-new')) self._widget.refresh_graph_push_button.pressed.connect(self._update_conductor_graph) self._widget.highlight_connections_check_box.toggled.connect(self._redraw_graph_view) self._widget.auto_fit_graph_check_box.toggled.connect(self._redraw_graph_view) self._widget.fit_in_view_push_button.setIcon(QIcon.fromTheme('zoom-original')) self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view) self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() self._widget.tabWidget.currentChanged.connect(self._change_client_tab) self._client_list_update_signal.connect(self._update_conductor_graph) #rospy.Subscriber(concert_msgs.Strings.CONCERT_CLIENT_CHANGES, ConcertClients, self._update_client_list) context.add_widget(self._widget)
def __init__(self, context): self._context = context super(ConductorGraph, self).__init__(context) self.initialised = False self.setObjectName('Conductor Graph') self._node_items = None self._edge_items = None self._node_item_events = {} self._edge_item_events = {} self._client_info_list = {} self._widget = QWidget() self.cur_selected_client_name = "" self.pre_selected_client_name = "" # factory builds generic dotcode items self.dotcode_factory = PydotFactory() # self.dotcode_factory=PygraphvizFactory() self.dotcode_generator = ConductorGraphDotcodeGenerator() self.dot_to_qt = DotToQtGenerator() self._graph = ConductorGraphInfo(self._update_conductor_graph_relay, self._set_network_statisics) rospack = rospkg.RosPack() ui_file = os.path.join(rospack.get_path('concert_conductor_graph'), 'ui', 'conductor_graph.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('ConductorGraphUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.highlight_connections_check_box.toggled.connect( self._redraw_graph_view) self._widget.auto_fit_graph_check_box.toggled.connect( self._redraw_graph_view) self._widget.clusters_check_box.toggled.connect( self._redraw_graph_view) self.signal_deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self.signal_deferred_fit_in_view.emit() self._widget.tabWidget.currentChanged.connect(self._change_client_tab) self.signal_update_conductor_graph.connect( self._update_conductor_graph) context.add_widget(self._widget)
def __init__(self, context): super(Ros2KnowledgeGraph, self).__init__(context) self._node = context.node self._logger = self._node.get_logger().get_child( 'ros2_knowledge_graph_viewer.ros2_knowledge_graph.Ros2KnowledgeGraph' ) self.setObjectName('Ros2KnowledgeGraph') self._ros2_knowledge_graph = Ros2KnowledgeGraphImpl() self._current_dotcode = None self._widget = QWidget() self.dotcode_factory = PydotFactory() self.dotcode_generator = Ros2KnowledgeGraphDotcodeGenerator() self.dot_to_qt = DotToQtGenerator() _, package_path = get_resource('packages', 'ros2_knowledge_graph_viewer') ui_file = os.path.join(package_path, 'share', 'ros2_knowledge_graph_viewer', 'resource', 'Ros2KnowledgeGraph.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('Ros2KnowledgeGraphUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.save_as_svg_push_button.setIcon( QIcon.fromTheme('document-save-as')) self._widget.save_as_svg_push_button.pressed.connect(self._save_svg) self._widget.save_as_image_push_button.setIcon( QIcon.fromTheme('image')) self._widget.save_as_image_push_button.pressed.connect( self._save_image) self._update_ros2_knowledge_graph() self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() context.add_widget(self._widget) self._updateTimer = QtCore.QTimer() self._updateTimer.timeout.connect(self.do_update) self._updateTimer.start(10)
def test_label_sizes(self): (nodes, edges) = DotToQtGenerator().dotcode_to_qt_items(DotToQtGeneratorTest.DOT_CODE, 1) self.longMessage = True for name, node in nodes.items(): shape_rect = node._graphics_item.sceneBoundingRect() label_rect = node._label.sceneBoundingRect() self.assertLess( label_rect.width(), shape_rect.width(), 'Label text for "%s" is wider than surrounding shape.' % name) self.assertLess( label_rect.height(), shape_rect.height(), 'Label text for "%s" is higher than surrounding shape.' % name)
def test_label_sizes(self): if DotToQtGeneratorTest._Q_APP is None: raise unittest.case.SkipTest (nodes, edges) = DotToQtGenerator().dotcode_to_qt_items( DotToQtGeneratorTest.DOT_CODE, 1) self.longMessage = True for name, node in nodes.items(): shape_rect = node._graphics_item.sceneBoundingRect() label_rect = node._label.sceneBoundingRect() self.assertLess( label_rect.width(), shape_rect.width(), "Label text for '%s' is wider than surrounding shape." % name) self.assertLess( label_rect.height(), shape_rect.height(), "Label text for '%s' is higher than surrounding shape." % name)
def __init__(self, context): super(CapabilityGraph, self).__init__(context) self.setObjectName('CapabilityGraph') self.__current_dotcode = None self.__running_providers = [] self.__spec_index = None self.__widget = QWidget() self.__dot_to_qt = DotToQtGenerator() rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('rqt_capabilities'), 'resources', 'CapabilityGraph.ui') loadUi( ui_file, self.__widget, { 'CapabilitiesInteractiveGraphicsView': CapabilitiesInteractiveGraphicsView }) self.__widget.setObjectName('CapabilityGraphUI') if context.serial_number() > 1: self.__widget.setWindowTitle(self.__widget.windowTitle() + (' (%d)' % context.serial_number())) self.__scene = QGraphicsScene() self.__scene.setBackgroundBrush(Qt.white) self.__widget.graphics_view.setScene(self.__scene) self.__widget.refresh_graph_push_button.setIcon( QIcon.fromTheme('view-refresh')) self.__widget.refresh_graph_push_button.pressed.connect( self.__refresh_view) self.__refresh_view() self.__deferred_fit_in_view.connect(self.__fit_in_view, Qt.QueuedConnection) self.__deferred_fit_in_view.emit() self.__redraw_graph.connect(self.__update_capabilities_graph) # TODO: use user provided server node name rospy.Subscriber('/capability_server/events', CapabilityEvent, self.__handle_event) context.add_widget(self.__widget)
def __init__(self, dotFile, maxDistance): """ * dotfile -- the path to the dot file to load * maxDistance -- the maximum distance from the node to allow """ QtGui.QWidget.__init__(self) self.__dotFile = dotFile self.__maxDistance = maxDistance # Load the graph from the dot file self.__graph = DotFileGraph(dotFile) self.__dotcode = None # Create a layout for the widget self.__layout = QtGui.QVBoxLayout() self.setLayout(self.__layout) # Create the graphics scene and view to display the graph self.__scene = QtGui.QGraphicsScene() self.__scene.setBackgroundBrush(Qt.white) self.__view = QtGui.QGraphicsView() self.__view.setScene(self.__scene) self.__layout.addWidget(self.__view) # Create a slider to change the parent depth self.__aboveSlider, self.__aboveLabel = self.__createDistanceSlider( "Distance above", self.__graph.getAboveDistance(), self.__onAboveDistance) # Create a slider to change the child depth self.__belowSlider, self.__belowLabel = self.__createDistanceSlider( "Distance below", self.__graph.getBelowDistance(), self.__onBelowDistance) # Create a list to view all nodes self.__createNodeListWidget() # Generates QT widgets from dot code self.__dotToQt = DotToQtGenerator() # Do the initial display of the graph self.updateGraph() self.setGeometry(0, 0, 1000, 600)
def __init__(self): super(BTWidget, self).__init__() self.setObjectName('BTWidget') self._graph = None self._current_dotcode = None self._initialized = False # dot_to_qt transforms into Qt elements using dot layout self.dot_to_qt = DotToQtGenerator() rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('rqt_bt'), 'resource', 'rqt_bt.ui') loadUi(ui_file, self, {'InteractiveGraphicsView': InteractiveGraphicsView}) self.refresh_timer = QTimer(self) self.refresh_timer.start(self._redraw_interval) self.refresh_timer.timeout.connect(self._refresh_rosgraph) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self.graphics_view.setScene(self._scene) self.refresh_graph_push_button.setIcon(QIcon.fromTheme('view-refresh')) self.refresh_graph_push_button.clicked.connect(self._update_rosgraph) self.highlight_connections_check_box.toggled.connect( self._redraw_graph_view) self.auto_fit_graph_check_box.toggled.connect(self._redraw_graph_view) self.fit_in_view_push_button.setIcon(QIcon.fromTheme('zoom-original')) self.fit_in_view_push_button.clicked.connect(self._fit_in_view) self.depth_spin_box.setMinimum(-1) self.depth_spin_box.valueChanged.connect(self._refresh_rosgraph) self.save_dot_push_button.setIcon(QIcon.fromTheme('document-save-as')) self.save_dot_push_button.clicked.connect(self._save_dot) self.save_as_svg_push_button.setIcon( QIcon.fromTheme('document-save-as')) self.save_as_svg_push_button.clicked.connect(self._save_svg) self.save_as_image_push_button.setIcon(QIcon.fromTheme('image')) self.save_as_image_push_button.clicked.connect(self._save_image) self.run_push_button.setIcon(QIcon.fromTheme('media-playback-pause')) self.run_push_button.clicked.connect(self._run_bt) self._update_rosgraph() self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() # generator builds tree graph bt_sub_name = '/cyborg/bt/behavior_tree' bt_update_sub_name = '/cyborg/bt/behavior_tree_updates' bt_enabled_sub_name = '/cyborg/bt/enabled' bt_enable_srv_name = '/cyborg/bt/enable' self._bt_enabled = True rospy.Subscriber(bt_enabled_sub_name, Bool, self._bt_enabled_cb) self._bt_enable_srv = rospy.ServiceProxy(bt_enable_srv_name, SetBool) bt_data = BTData(bt_sub_name, bt_update_sub_name) self.dotcode_generator = RosBTDotcodeGenerator(bt_data)
def __init__(self, context): super(VinoGraph, self).__init__(context) # Give QObjects reasonable names self.setObjectName('VinoGraph') # Process standalone plugin command-line arguments from argparse import ArgumentParser parser = ArgumentParser() # Add argument(s) to the parser. parser.add_argument("-q", "--quiet", action="store_true", dest="quiet", help="Put plugin in silent mode") args, unknowns = parser.parse_known_args(context.argv()) if not args.quiet: print 'arguments: ', args print 'unknowns: ', unknowns # Create QWidget self._widget = QWidget() # Get path to UI file which should be in the "resource" folder of this package ui_file = os.path.join(rospkg.RosPack().get_path('rqt_vino_plugin'), 'resource', 'rqt_vino_plugin.ui') # Extend the widget with all attributes and children from UI file loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) # Give QObjects reasonable names self._widget.setObjectName('VinoGraphUi') # Show _widget.windowTitle on left-top of each plugin (when # it's set in _widget). This is useful when you open multiple QListView # plugins at once. Also if you open multiple instances of your # plugin at once, these lines add number to make it easy to # tell from pane to pane. if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) #A dict which stores pipeline name and dotgraph pair self._dotgraphs = dict() #which dotgraph currently drawing on the scence self._current_dotcode = None self._current_pipeline_name = '' #Pydot self.dotcode_factory = VinoPydotFactory() self.dot_to_qt = DotToQtGenerator() self.param_manager = ParamManagerWrapper() #Binding scene canvas self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.graphics_view.setClickNodeCallback(self._edit_node) #QListview of pipelines self._listmodel = QStandardItemModel() self._widget.pipeline_name_listview.clicked.connect( self._display_choosed_pipeline) #self._widget.pipeline_name_listview.itemRenamed.connect(self._rename_pipeline) #Load pipelines from yaml file self._widget.load_pipeline_push_button.clicked.connect( self._load_pipeline) #Create a pipeline self._widget.create_pipeline_push_button.clicked.connect( self._create_pipeline) #Add input to pipeline graph self._widget.add_input_push_button.clicked.connect(self._add_input) #Add infer self._widget.add_inference_push_button.clicked.connect(self._add_infer) self._widget.add_output_push_button.clicked.connect(self._add_output) self._widget.save_pipeline_push_button.clicked.connect( self._save_pipeline) self.models_desc_file_path = os.path.join( rospkg.RosPack().get_path('vino_param_lib'), 'param', 'models.yaml') # Add widget to the user interface context.add_widget(self._widget)
def test_recursive(self): if DotToQtGeneratorTest._Q_APP is None: raise unittest.case.SkipTest gen = DotToQtGenerator() dotcode = r''' strict digraph "" { graph [bb="0,0,249,541", compound=True, rank=same, rankdir=TB, ranksep=0.2, simplify=True ]; node [label="\N"]; subgraph "/Container" { graph [bb="8,67,241,321", color=None, compound=True, label="/Container", lheight=0.21, lp="124.5,309.5", lwidth=0.81, rank=same, rankdir=TB, ranksep=0.2, style=bold ]; subgraph "/Container/Subcontainer" { graph [bb="84,142,233,287", color=None, compound=True, label="/Container/Subcontainer", lheight=0.21, lp="158.5,275.5", lwidth=1.85, rank=same, rankdir=TB, ranksep=0.2, style=bold ]; "/Container/Subcontainer/logstate1" [height=0.5, label=logstate1, pos="133,235", shape=box, url=None, width=0.90278]; "/Container/Subcontainer/finished" [color=blue, height=0.5, label=finished, pos="133,168", shape=ellipse, url=None, width=1.0833]; "/Container/Subcontainer/logstate1" -> "/Container/Subcontainer/finished" [label=done, lp="146.5,201.5", pos="e,133,186.19 133,216.92 133,210.7 133,203.5 133,196.6", url=None]; } "/Container/finished" [color=blue, height=0.5, label=finished, pos="86,93", shape=ellipse, url=None, width=1.0833]; "/Container/Subcontainer/finished" -> "/Container/finished" [label=finished, lp="132,126.5", pos="e,96.623,110.5 122.33,150.44 116.39,141.19 108.85,129.5 102.19,119.15", url=None]; "/Container/logstate" [height=0.5, label=logstate, pos="46,168", shape=box, url=None, width=0.81944]; "/Container/logstate" -> "/Container/finished" [label=done, lp="82.5,126.5", pos="e,74.304,110.45 53.482,149.8 57.712,140.5 63.287,128.93 69,119 69.051,118.91 69.102,118.82 69.153,118.74", url=None]; } "/finished" [height=0.5, pos="86,18", width=1.1555]; "/Container/finished" -> "/finished" [label=finished, lp="108,51.5", pos="e,86,36.176 86,74.7 86,66.245 86,55.869 86,46.373", url=None]; "/start" -> "/Container/Subcontainer/logstate1" [ lp="146.5,436.5", pos="e,133,250.01 133,355.84 133,337.5 133,316.81 133,260.22", url=None]; "/start" -> "/Container/logstate" [ lp="146.5,436.5", pos="e,46,185.01 133,355.84 46,337.5 46,316.81 46,192.22", url=None]; "/start" [height=0.5, pos="133,373", width=0.79437]; } ''' (nodes, edges) = gen.dotcode_to_qt_items(dotcode, 1) expected_nodes = [ '"/Container"', '"/Container/Subcontainer"', '"/Container/Subcontainer/finished"', '"/Container/Subcontainer/logstate1"', '"/Container/finished"', '"/Container/logstate"', '"/finished"', '"/start"' ] expected_edges = [ '/Container/Subcontainer/finished_TO_/Container/finished_finished', '/Container/Subcontainer/logstate1_TO_/Container/Subcontainer/finished_done', '/Container/finished_TO_/finished_finished', '/Container/logstate_TO_/Container/finished_done', '/start_TO_/Container/Subcontainer/logstate1', '/start_TO_/Container/logstate', ] nodes_sorted = list(sorted(nodes.keys())) edges_sorted = list(sorted(edges.keys())) self.assertEqual(expected_nodes, nodes_sorted) self.assertEqual(expected_edges, edges_sorted)
def __init__(self, context): super(RosGraph, self).__init__(context) self.initialized = False self.setObjectName('RosGraph') self._graph = None self._current_dotcode = None self._widget = QWidget() # factory builds generic dotcode items self.dotcode_factory = PydotFactory() # self.dotcode_factory = PygraphvizFactory() # generator builds rosgraph self.dotcode_generator = RosGraphDotcodeGenerator() # dot_to_qt transforms into Qt elements using dot layout self.dot_to_qt = DotToQtGenerator() ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'RosGraph.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('RosGraphUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.graph_type_combo_box.insertItem(0, self.tr('Nodes only'), NODE_NODE_GRAPH) self._widget.graph_type_combo_box.insertItem(1, self.tr('Nodes/Topics (active)'), NODE_TOPIC_GRAPH) self._widget.graph_type_combo_box.insertItem(2, self.tr('Nodes/Topics (all)'), NODE_TOPIC_ALL_GRAPH) self._widget.graph_type_combo_box.setCurrentIndex(0) self._widget.graph_type_combo_box.currentIndexChanged.connect(self._refresh_rosgraph) self.node_completionmodel = NamespaceCompletionModel(self._widget.filter_line_edit, False) completer = RepeatedWordCompleter(self.node_completionmodel, self) completer.setCompletionMode(QCompleter.PopupCompletion) completer.setWrapAround(True) completer.setCaseSensitivity(Qt.CaseInsensitive) self._widget.filter_line_edit.editingFinished.connect(self._refresh_rosgraph) self._widget.filter_line_edit.setCompleter(completer) self.topic_completionmodel = NamespaceCompletionModel(self._widget.topic_filter_line_edit, False) topic_completer = RepeatedWordCompleter(self.topic_completionmodel, self) topic_completer.setCompletionMode(QCompleter.PopupCompletion) topic_completer.setWrapAround(True) topic_completer.setCaseSensitivity(Qt.CaseInsensitive) self._widget.topic_filter_line_edit.editingFinished.connect(self._refresh_rosgraph) self._widget.topic_filter_line_edit.setCompleter(topic_completer) self._widget.namespace_cluster_check_box.clicked.connect(self._refresh_rosgraph) self._widget.actionlib_check_box.clicked.connect(self._refresh_rosgraph) self._widget.dead_sinks_check_box.clicked.connect(self._refresh_rosgraph) self._widget.leaf_topics_check_box.clicked.connect(self._refresh_rosgraph) self._widget.quiet_check_box.clicked.connect(self._refresh_rosgraph) self._widget.refresh_graph_push_button.setIcon(QIcon.fromTheme('view-refresh')) self._widget.refresh_graph_push_button.pressed.connect(self._update_rosgraph) self._widget.highlight_connections_check_box.toggled.connect(self._redraw_graph_view) self._widget.auto_fit_graph_check_box.toggled.connect(self._redraw_graph_view) self._widget.fit_in_view_push_button.setIcon(QIcon.fromTheme('zoom-original')) self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view) self._widget.load_dot_push_button.setIcon(QIcon.fromTheme('document-open')) self._widget.load_dot_push_button.pressed.connect(self._load_dot) self._widget.save_dot_push_button.setIcon(QIcon.fromTheme('document-save-as')) self._widget.save_dot_push_button.pressed.connect(self._save_dot) self._widget.save_as_svg_push_button.setIcon(QIcon.fromTheme('document-save-as')) self._widget.save_as_svg_push_button.pressed.connect(self._save_svg) self._widget.save_as_image_push_button.setIcon(QIcon.fromTheme('image')) self._widget.save_as_image_push_button.pressed.connect(self._save_image) self._update_rosgraph() self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() context.add_widget(self._widget)
def __init__(self, context): super(RosPackGraph, self).__init__(context) self.initialized = False self._current_dotcode = None self._update_thread = WorkerThread(self._update_thread_run, self._update_finished) self._nodes = {} self._edges = {} self._options = {} self._options_serialized = '' self.setObjectName('RosPackGraph') rospack = rospkg.RosPack() rosstack = rospkg.RosStack() # factory builds generic dotcode items self.dotcode_factory = PydotFactory() # self.dotcode_factory = PygraphvizFactory() # generator builds rosgraph self.dotcode_generator = RosPackageGraphDotcodeGenerator( rospack, rosstack) # dot_to_qt transforms into Qt elements using dot layout self.dot_to_qt = DotToQtGenerator() self._widget = QWidget() rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('rqt_dep'), 'resource', 'RosPackGraph.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('RosPackGraphUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.depth_combo_box.insertItem(0, self.tr('infinite'), -1) self._widget.depth_combo_box.insertItem(1, self.tr('1'), 2) self._widget.depth_combo_box.insertItem(2, self.tr('2'), 3) self._widget.depth_combo_box.insertItem(3, self.tr('3'), 4) self._widget.depth_combo_box.insertItem(4, self.tr('4'), 5) self._widget.depth_combo_box.currentIndexChanged.connect( self._refresh_rospackgraph) self._widget.directions_combo_box.insertItem(0, self.tr('depends'), 0) self._widget.directions_combo_box.insertItem(1, self.tr('depends_on'), 1) self._widget.directions_combo_box.insertItem(2, self.tr('both'), 2) self._widget.directions_combo_box.currentIndexChanged.connect( self._refresh_rospackgraph) self._widget.package_type_combo_box.insertItem(0, self.tr('wet & dry'), 3) self._widget.package_type_combo_box.insertItem(1, self.tr('wet only'), 2) self._widget.package_type_combo_box.insertItem(2, self.tr('dry only'), 1) self._widget.package_type_combo_box.currentIndexChanged.connect( self._refresh_rospackgraph) completionmodel = StackageCompletionModel( self._widget.filter_line_edit, rospack, rosstack) completer = RepeatedWordCompleter(completionmodel, self) completer.setCompletionMode(QCompleter.PopupCompletion) completer.setWrapAround(True) completer.setCaseSensitivity(Qt.CaseInsensitive) self._widget.filter_line_edit.editingFinished.connect( self._refresh_rospackgraph) self._widget.filter_line_edit.setCompleter(completer) self._widget.filter_line_edit.selectionChanged.connect( self._clear_filter) self._widget.with_stacks_check_box.clicked.connect( self._refresh_rospackgraph) self._widget.mark_check_box.clicked.connect(self._refresh_rospackgraph) self._widget.colorize_check_box.clicked.connect( self._refresh_rospackgraph) self._widget.hide_transitives_check_box.clicked.connect( self._refresh_rospackgraph) self._widget.show_system_check_box.clicked.connect( self._refresh_rospackgraph) self._widget.refresh_graph_push_button.setIcon( QIcon.fromTheme('view-refresh')) self._widget.refresh_graph_push_button.pressed.connect( self._update_rospackgraph) self._widget.highlight_connections_check_box.toggled.connect( self._refresh_rospackgraph) self._widget.auto_fit_graph_check_box.toggled.connect( self._refresh_rospackgraph) self._widget.fit_in_view_push_button.setIcon( QIcon.fromTheme('zoom-original')) self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view) self._widget.load_dot_push_button.setIcon( QIcon.fromTheme('document-open')) self._widget.load_dot_push_button.pressed.connect(self._load_dot) self._widget.save_dot_push_button.setIcon( QIcon.fromTheme('document-save-as')) self._widget.save_dot_push_button.pressed.connect(self._save_dot) self._widget.save_as_svg_push_button.setIcon( QIcon.fromTheme('document-save-as')) self._widget.save_as_svg_push_button.pressed.connect(self._save_svg) self._widget.save_as_image_push_button.setIcon( QIcon.fromTheme('image')) self._widget.save_as_image_push_button.pressed.connect( self._save_image) self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() context.add_widget(self._widget) # If in either of following case, this turnes True # - 1st filtering key is already input by user # - filtering key is restored self._filtering_started = False
def test_simpleIntegration(self): gen = DotToQtGenerator() dotcode = 'digraph graphname {\n\tgraph [rank=same];\n\tnode [label="\\N"];\n\tgraph [bb="0,0,56,116"];\n\tsubgraph cluster_foo {\n\t\tgraph [label=foo,\n\t\t\tbb="1,1,100,101"];\n\t}\n\tfoo [label=foo, shape=box, pos="28,98", width="0.75", height="0.50"];\n\tedge_ [label=edge_, shape=box, pos="28,26", width="0.78", height="0.50"];\n\tfoo -> edge_ [pos="e,28,44 28,80 28,72 28,63 28,54"];\n}\n' (nodes, edges) = gen.dotcode_to_qt_items(dotcode, 1) self.assertEqual(3, len(nodes)) # also for stack self.assertEqual(1, len(nodes))
def test_simple_integration(self): (nodes, edges) = DotToQtGenerator().dotcode_to_qt_items(DotToQtGeneratorTest.DOT_CODE, 1) self.assertEqual(3, len(nodes)) # cluster_foo, foo and bar self.assertEqual(1, len(edges)) # foo -> bar
def __init__(self, context): super(RosBehaviourTree, self).__init__(context) self.setObjectName('RosBehaviourTree') parser = argparse.ArgumentParser() RosBehaviourTree.add_arguments(parser, False) # if the context doesn't have an argv attribute then assume we're running with --no-roscore if not hasattr(context, 'argv'): args = sys.argv[1:] # Can run the viewer with or without live updating. Running without is # intended for viewing of bags only self.live_update = False else: args = context.argv() self.live_update = True parsed_args = parser.parse_args(args) self.context = context self.initialized = False self._current_dotcode = None # dotcode for the tree that is currently displayed self._viewing_bag = False # true if a bag file is loaded # True if next or previous buttons are pressed. Reset if the tree being # viewed is the last one in the list. self._browsing_timeline = False self._widget = QWidget() # factory builds generic dotcode items self.dotcode_factory = PygraphvizFactory() # PydotFactory() # self.dotcode_factory = PygraphvizFactory() # generator builds rosgraph self.dotcode_generator = RosBehaviourTreeDotcodeGenerator() self.current_topic = None self.behaviour_sub = None self._tip_message = None # message of the tip of the tree self._saved_settings_topic = None # topic subscribed to by previous instance self.visibility_level = py_trees.common.VisibilityLevel.DETAIL # dot_to_qt transforms into Qt elements using dot layout self.dot_to_qt = DotToQtGenerator() rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('rqt_py_trees'), 'resource', 'RosBehaviourTree.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('RosBehaviourTreeUi') if hasattr(context, 'serial_number') and context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.highlight_connections_check_box.toggled.connect( self._redraw_graph_view) self._widget.auto_fit_graph_check_box.toggled.connect( self._redraw_graph_view) self._widget.fit_in_view_push_button.setIcon( QIcon.fromTheme('zoom-original')) self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view) self._widget.load_bag_push_button.setIcon( QIcon.fromTheme('document-open')) self._widget.load_bag_push_button.pressed.connect(self._load_bag) self._widget.load_dot_push_button.setIcon( QIcon.fromTheme('document-open')) self._widget.load_dot_push_button.pressed.connect(self._load_dot) self._widget.save_dot_push_button.setIcon( QIcon.fromTheme('document-save-as')) self._widget.save_dot_push_button.pressed.connect(self._save_dot) self._widget.save_as_svg_push_button.setIcon( QIcon.fromTheme('document-save-as')) self._widget.save_as_svg_push_button.pressed.connect(self._save_svg) self._widget.save_as_image_push_button.setIcon( QIcon.fromTheme('image')) self._widget.save_as_image_push_button.pressed.connect( self._save_image) for text in visibility.combo_to_py_trees: self._widget.visibility_level_combo_box.addItem(text) self._widget.visibility_level_combo_box.setCurrentIndex( self.visibility_level) self._widget.visibility_level_combo_box.currentIndexChanged[ 'QString'].connect(self._update_visibility_level) # set up the function that is called whenever the box is resized - # ensures that the timeline is correctly drawn. self._widget.resizeEvent = self._resize_event self._timeline = None self._timeline_listener = None # Connect the message changed function of this object to a corresponding # signal. This signal will be activated whenever the message being # viewed changes. self._message_changed.connect(self.message_changed) self._message_cleared.connect(self.message_cleared) # Set up combo box for topic selection # when the refresh_combo signal happens, update the combo topics available self._refresh_combo.connect(self._update_combo_topics) # filter events to catch the event which opens the combo box self._combo_event_filter = RosBehaviourTree.ComboBoxEventFilter( self._refresh_combo) self._widget.topic_combo_box.installEventFilter( self._combo_event_filter) self._widget.topic_combo_box.activated.connect(self._choose_topic) self._update_combo_topics() # Set up navigation buttons self._widget.previous_tool_button.pressed.connect(self._previous) self._widget.previous_tool_button.setIcon( QIcon.fromTheme('go-previous')) self._widget.next_tool_button.pressed.connect(self._next) self._widget.next_tool_button.setIcon(QIcon.fromTheme('go-next')) self._widget.first_tool_button.pressed.connect(self._first) self._widget.first_tool_button.setIcon(QIcon.fromTheme('go-first')) self._widget.last_tool_button.pressed.connect(self._last) self._widget.last_tool_button.setIcon(QIcon.fromTheme('go-last')) # play, pause and stop buttons self._widget.play_tool_button.pressed.connect(self._play) self._widget.play_tool_button.setIcon( QIcon.fromTheme('media-playback-start')) self._widget.stop_tool_button.pressed.connect(self._stop) self._widget.stop_tool_button.setIcon( QIcon.fromTheme('media-playback-stop')) # also connect the navigation buttons so that they stop the timer when # pressed while the tree is playing. self._widget.first_tool_button.pressed.connect(self._stop) self._widget.previous_tool_button.pressed.connect(self._stop) self._widget.last_tool_button.pressed.connect(self._stop) self._widget.next_tool_button.pressed.connect(self._stop) # set up shortcuts for navigation (vim) next_shortcut_vi = QShortcut(QKeySequence("l"), self._widget) next_shortcut_vi.activated.connect( self._widget.next_tool_button.pressed) previous_shortcut_vi = QShortcut(QKeySequence("h"), self._widget) previous_shortcut_vi.activated.connect( self._widget.previous_tool_button.pressed) first_shortcut_vi = QShortcut(QKeySequence("^"), self._widget) first_shortcut_vi.activated.connect( self._widget.first_tool_button.pressed) last_shortcut_vi = QShortcut(QKeySequence("$"), self._widget) last_shortcut_vi.activated.connect( self._widget.last_tool_button.pressed) # shortcuts for emacs next_shortcut_emacs = QShortcut(QKeySequence("Ctrl+f"), self._widget) next_shortcut_emacs.activated.connect( self._widget.next_tool_button.pressed) previous_shortcut_emacs = QShortcut(QKeySequence("Ctrl+b"), self._widget) previous_shortcut_emacs.activated.connect( self._widget.previous_tool_button.pressed) first_shortcut_emacs = QShortcut(QKeySequence("Ctrl+a"), self._widget) first_shortcut_emacs.activated.connect( self._widget.first_tool_button.pressed) last_shortcut_emacs = QShortcut(QKeySequence("Ctrl+e"), self._widget) last_shortcut_emacs.activated.connect( self._widget.last_tool_button.pressed) # set up stuff for dotcode cache self._dotcode_cache_capacity = 50 self._dotcode_cache = {} # cache is ordered on timestamps from messages, but earliest timestamp # isn't necessarily the message that was viewed the longest time ago, so # need to store keys self._dotcode_cache_keys = [] # set up stuff for scene cache (dotcode cache doesn't seem to make much difference) self._scene_cache_capacity = 50 self._scene_cache = {} self._scene_cache_keys = [] # Update the timeline buttons to correspond with a completely # uninitialised state. self._set_timeline_buttons(first_snapshot=False, previous_snapshot=False, next_snapshot=False, last_snapshot=False) self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() # This is used to store a timer which controls how fast updates happen when the play button is pressed. self._play_timer = None # updates the view self._refresh_view.connect(self._refresh_tree_graph) self._force_refresh = False if self.live_update: context.add_widget(self._widget) else: self.initialized = True # this needs to be set for trees to be displayed context.setCentralWidget(self._widget) if parsed_args.bag: self._load_bag(parsed_args.bag) elif parsed_args.latest_bag: # if the latest bag is requested, load it from the default directory, or # the one specified in the args bag_dir = parsed_args.bag_dir or os.getenv( 'ROS_HOME', os.path.expanduser('~/.ros')) + '/behaviour_trees' self.open_latest_bag(bag_dir, parsed_args.by_time)
def __init__(self, context): super(GatewayGraph, self).__init__(context) self.initialised = False self.setObjectName('Gateway Graph') self._current_dotcode = None self._widget = QWidget() # factory builds generic dotcode items self.dotcode_factory = PydotFactory() # self.dotcode_factory = PygraphvizFactory() self.dotcode_generator = RosGraphDotcodeGenerator() self.dot_to_qt = DotToQtGenerator() self._graph = Graph() rospack = rospkg.RosPack() ui_file = os.path.join(rospack.get_path('rocon_gateway_graph'), 'ui', 'gateway_graph.ui') #ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ui', 'gateway_graph.ui') loadUi(ui_file, self._widget, {'InteractiveGraphicsView': InteractiveGraphicsView}) self._widget.setObjectName('GatewayGraphUi') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) self._scene = QGraphicsScene() self._scene.setBackgroundBrush(Qt.white) self._widget.graphics_view.setScene(self._scene) self._widget.refresh_graph_push_button.setIcon( QIcon.fromTheme('view-refresh')) self._widget.refresh_graph_push_button.pressed.connect( self._update_gateway_graph) self._widget.graph_type_combo_box.insertItem(0, self.tr('Gateways'), GATEWAY_GATEWAY_GRAPH) self._widget.graph_type_combo_box.insertItem( 1, self.tr('Pulled Connections'), GATEWAY_PULLED_GRAPH) self._widget.graph_type_combo_box.insertItem( 2, self.tr('Flipped Connections'), GATEWAY_FLIPPED_GRAPH) self._widget.graph_type_combo_box.setCurrentIndex(0) self._widget.graph_type_combo_box.currentIndexChanged.connect( self._refresh_rosgraph) self.node_completionmodel = NamespaceCompletionModel( self._widget.filter_line_edit, False) completer = RepeatedWordCompleter(self.node_completionmodel, self) completer.setCompletionMode(QCompleter.PopupCompletion) completer.setWrapAround(True) completer.setCaseSensitivity(Qt.CaseInsensitive) self._widget.filter_line_edit.editingFinished.connect( self._refresh_rosgraph) self._widget.filter_line_edit.setCompleter(completer) self.topic_completionmodel = NamespaceCompletionModel( self._widget.topic_filter_line_edit, False) topic_completer = RepeatedWordCompleter(self.topic_completionmodel, self) topic_completer.setCompletionMode(QCompleter.PopupCompletion) topic_completer.setWrapAround(True) topic_completer.setCaseSensitivity(Qt.CaseInsensitive) self._widget.topic_filter_line_edit.editingFinished.connect( self._refresh_rosgraph) self._widget.topic_filter_line_edit.setCompleter(topic_completer) self._widget.namespace_cluster_check_box.clicked.connect( self._refresh_rosgraph) self._widget.watchlist_check_box.clicked.connect( self._refresh_rosgraph) self._widget.all_advertisements_check_box.clicked.connect( self._refresh_rosgraph) self._widget.highlight_connections_check_box.toggled.connect( self._redraw_graph_view) self._widget.auto_fit_graph_check_box.toggled.connect( self._redraw_graph_view) self._widget.fit_in_view_push_button.setIcon( QIcon.fromTheme('zoom-original')) self._widget.fit_in_view_push_button.pressed.connect(self._fit_in_view) self._widget.load_dot_push_button.setIcon( QIcon.fromTheme('document-open')) self._widget.load_dot_push_button.pressed.connect(self._load_dot) self._widget.save_dot_push_button.setIcon( QIcon.fromTheme('document-save-as')) self._widget.save_dot_push_button.pressed.connect(self._save_dot) self._widget.save_as_svg_push_button.setIcon( QIcon.fromTheme('document-save-as')) self._widget.save_as_svg_push_button.pressed.connect(self._save_svg) self._widget.save_as_image_push_button.setIcon( QIcon.fromTheme('image')) self._widget.save_as_image_push_button.pressed.connect( self._save_image) self._update_gateway_graph() self._deferred_fit_in_view.connect(self._fit_in_view, Qt.QueuedConnection) self._deferred_fit_in_view.emit() context.add_widget(self._widget)