Esempio n. 1
0
class QtRappManager(Plugin):
    _update_rapps_signal = Signal()

    def __init__(self, context):
        self._context = context
        super(QtRappManager, self).__init__(context)

        self._init_ui(context)
        self._init_events()
        self._init_variables()
        self.spin()

    def _init_ui(self, context):
        self._widget = QWidget()
        self.setObjectName('QtRappManger')

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_qt_app_manager'), 'ui',
                               'qt_rapp_manager.ui')
        self._widget.setObjectName('QtRappManger')
        loadUi(ui_file, self._widget, {})

        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))
        context.add_widget(self._widget)

        # Set view mode
        self._widget.rapp_grid.setViewMode(QListView.IconMode)
        # self._widget.rapp_grid.setViewMode(QListView.ListMode)

    def _init_events(self):
        # combo box change event
        self._widget.namespace_cbox.currentIndexChanged.connect(
            self._change_namespace)

        # Rapp single click event
        self._widget.rapp_grid.clicked.connect(self._rapp_single_click)
        # Rapp double click event
        self._widget.rapp_grid.doubleClicked.connect(self._rapp_double_click)

    def _init_variables(self):
        self.initialised = False

        # init
        self._qt_rapp_manager_info = QtRappManagerInfo(self._refresh_rapps)
        self._update_rapps_signal.connect(self._update_rapp_list)

        self._rapp_view_model = QStandardItemModel()
        self._widget.rapp_grid.setModel(self._rapp_view_model)
        self._widget.rapp_grid.setWrapping(True)
        self._widget.rapp_grid.setIconSize(QSize(60, 60))
        self._widget.rapp_grid.setSpacing(10)

        self._selected_rapp = None

    def spin(self):
        self._get_appmanager_namespaces()

    def _cleanup_rapps(self):
        self._rapp_view_model.clear()

    def _get_appmanager_namespaces(self):
        namespaces = self._qt_rapp_manager_info._get_namespaces()
        for namespace in namespaces:
            ns = namespace[:namespace.find('list_rapps')]
            self._widget.namespace_cbox.addItem(ns)

    def _exit(self):
        pass

###################################################################
# Events
###################################################################

    def _change_namespace(self, event):
        self._qt_rapp_manager_info.select_rapp_manager(
            self._widget.namespace_cbox.currentText())

    def _refresh_rapps(self):
        """
        Updates from qt_app_manager_info.
        """
        self._update_rapps_signal.emit()

    def _update_rapp_list(self):
        """
        Rapp manager namespace event
        """
        self._cleanup_rapps()
        available_rapps = self._qt_rapp_manager_info.get_available_rapps()
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()

        for r, v in available_rapps.items():
            if r in running_rapps.keys():
                item = QRappItem(v, running=True)
            else:
                item = QRappItem(v, running=False)
            self._rapp_view_model.appendRow(item)

    def _rapp_single_click(self, index):
        qrapp = self._rapp_view_model.item(index.row())
        rapp = qrapp.getRapp()
        self._create_rapp_dialog(rapp)

    def _create_rapp_dialog(self, rapp):
        is_running = self._qt_rapp_manager_info.is_running_rapp(rapp)
        self._selected_rapp = rapp
        self._dialog = QtRappDialog(self._widget, rapp,
                                    self._qt_rapp_manager_info.start_rapp,
                                    self._qt_rapp_manager_info.stop_rapp,
                                    is_running)
        self._dialog.show()

    def _rapp_double_click(self, item):
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()
        if len(running_rapps) > 0:
            names = [r['display_name'] for r in running_rapps.values()]
            show_message(self._widget, "Error",
                         "Rapp %s are already running" % names)
        else:
            self._start_rapp()

    def _start_rapp(self):
        result = self._qt_rapp_manager_info.start_rapp(
            self._selected_rapp['name'], [],
            self._selected_rapp['public_parameters'])
        show_message(self._widget, str(result.started), result.message)
        self._selected_rapp = None
        return result

    def _stop_rapp(self):
        result = self._qt_rapp_manager_info.stop_rapp()
        show_message(self._widget, str(result.stopped), result.message)
        self._selected_rapp = None
        return result
class QtRappManager(Plugin):
    _update_rapps_signal = Signal()

    def __init__(self, context):
        self._context = context
        super(QtRappManager, self).__init__(context)

        self._init_ui(context)
        self._init_events()
        self._init_variables()
        self.spin()

    def _init_ui(self, context):
        self._widget = QWidget()
        self.setObjectName('QtRappManger')

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_qt_app_manager'), 'ui',
                               'qt_rapp_manager.ui')
        self._widget.setObjectName('QtRappManger')
        loadUi(ui_file, self._widget, {})

        if context.serial_number() > 1:
            self._widget.setWindowTitle(self._widget.windowTitle() +
                                        (' (%d)' % context.serial_number()))
        context.add_widget(self._widget)

        # Set view mode
        self._widget.rapp_grid.setViewMode(QListView.IconMode)
        #self._widget.rapp_grid.setViewMode(QListView.ListMode)

    def _init_events(self):
        #combo box change event
        self._widget.namespace_cbox.currentIndexChanged.connect(
            self._change_namespace)

        # Rapp single click event
        self._widget.rapp_grid.clicked.connect(self._rapp_single_click)
        # Rapp double click event
        self._widget.rapp_grid.doubleClicked.connect(self._rapp_double_click)

    def _init_variables(self):
        self.initialised = False

        #init
        self._qt_rapp_manager_info = QtRappManagerInfo(self._refresh_rapps)
        self._update_rapps_signal.connect(self._update_rapp_list)

        self._rapp_view_model = QStandardItemModel()
        self._widget.rapp_grid.setModel(self._rapp_view_model)
        self._widget.rapp_grid.setWrapping(True)
        self._widget.rapp_grid.setIconSize(QSize(60, 60))
        self._widget.rapp_grid.setSpacing(10)

        self._selected_rapp = None

    def spin(self):
        self._get_appmanager_namespaces()

    def _cleanup_rapps(self):
        self._rapp_view_model.clear()
        pass

    def _get_appmanager_namespaces(self):
        namespaces = self._qt_rapp_manager_info._get_namespaces()
        for namespace in namespaces:
            ns = namespace[:namespace.find('list_rapps')]
            self._widget.namespace_cbox.addItem(ns)

    def _exit(self):
        pass

###################################################################
# Events
###################################################################

    def _change_namespace(self, event):
        self._qt_rapp_manager_info.select_rapp_manager(
            self._widget.namespace_cbox.currentText())

    def _refresh_rapps(self):
        """
        Updates from qt_app_manager_info.
        """
        self._update_rapps_signal.emit()

    def _update_rapp_list(self):
        """
        Rapp manager namespace event
        """
        self._cleanup_rapps()
        available_rapps = self._qt_rapp_manager_info.get_available_rapps()
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()

        rapp_items = []
        for r, v in available_rapps.items():
            if r in running_rapps.keys():
                item = QRappItem(v, running=True)
            else:
                item = QRappItem(v, running=False)
            self._rapp_view_model.appendRow(item)

    def _rapp_single_click(self, index):
        qrapp = self._rapp_view_model.item(index.row())
        rapp = qrapp.getRapp()
        self._create_rapp_dialog(rapp)

    def _create_rapp_dialog(self, rapp):
        is_running = self._qt_rapp_manager_info.is_running_rapp(rapp)
        self._selected_rapp = rapp
        self._dialog = QtRappDialog(self._widget, rapp,
                                    self._qt_rapp_manager_info.start_rapp,
                                    self._qt_rapp_manager_info.stop_rapp,
                                    is_running)
        self._dialog.show()

    def _rapp_double_click(self, item):
        running_rapps = self._qt_rapp_manager_info.get_running_rapps()
        if len(running_rapps) > 0:
            names = [r['display_name'] for r in running_rapps.values()]
            show_message(self._widget, "Error",
                         "Rapp %s are already running" % names)
        else:
            self._start_rapp()

    def _start_rapp(self):
        result = self._qt_rapp_manager_info.start_rapp(
            self._selected_rapp['name'], [],
            self._selected_rapp['public_parameters'])
        show_message(self._widget, str(result.started), result.message)
        self._selected_rapp = None
        return result

    def _stop_rapp(self):
        result = self._qt_rapp_manager_info.stop_rapp()
        show_message(self._widget, str(result.stopped), result.message)
        self._selected_rapp = None
        return result

########################################
# Legacy
########################################

    def _select_rapp_tree_item(self, item):
        if not item in self.rapps.keys():
            print "HAS NO KEY"
        else:
            self.current_rapp = self.rapps[item]
        self._widget.rapp_info_text.clear()
        rapp_info = self.qt_rapp_manager_info._get_rapp_info(self.current_rapp)
        self._widget.rapp_info_text.appendHtml(rapp_info)
        self._update_rapp_parameter_layout(self.current_rapp)
        self._update_implementation_tree(self.current_rapp)

    def _update_rapp_parameter_layout(self, rapp):
        parameters_layout = self._widget.rapp_parameter_layout
        clear_layout(parameters_layout)

        for param in rapp['public_parameters']:
            one_param_layout = create_label_textedit_pair(
                param.key, param.value)
            parameters_layout.addLayout(one_param_layout)

    def _update_implementation_tree(self, rapp):
        self._widget.implementation_tree_widget.clear()
        self.selected_impl = None
        self.impls = {}
        for impl in rapp['implementations']:
            impl_item = QTreeWidgetItem(
                self._widget.implementation_tree_widget)
            impl_item.setText(0, impl)
            self.impls[impl_item] = impl

    def _select_implementation_tree_item(self, item):
        if not item in self.impls.keys():
            print "HAS NO KEY"
        else:
            self.selected_impl = self.impls[item]

    def _get_public_parameters(self):
        public_parameters = {}
        parameters_layout = self._widget.rapp_parameter_layout
        for i in reversed(range(parameters_layout.count())):
            item = parameters_layout.itemAt(i)
            key_label = item.itemAt(0).widget()
            value_textbox = item.itemAt(1).widget()
            public_parameters[key_label.text()] = str(
                value_textbox.toPlainText())
        return public_parameters
Esempio n. 3
0
class Conman(Plugin):
    update_graph_sig = Signal(str)

    def __init__(self, context):
        super(Conman, self).__init__(context)

        self._dotcode_sub = None
        self._topic_dict = {}
        self._update_thread = WorkerThread(self._update_thread_run,
                                           self._update_finished)
        # Give QObjects reasonable names
        self.setObjectName('Conman')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'rqt_conman.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names

        self._widget.ns_refresh_button.setIcon(QIcon.fromTheme('view-refresh'))
        self._widget.setObjectName('ConmanPluginUi')
        # Show _widget.windowTitle on left-top of each plugin (when
        # it's set in _widget). This is useful when you open multiple
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #self._widget.subscribe_button.setCheckable(True)
        self._widget.namespace_input.currentIndexChanged.connect(
            self._handle_refresh_clicked)
        self._widget.ns_refresh_button.clicked.connect(self.refresh_combo_box)
        self._widget.refresh_button.clicked[bool].connect(
            self._handle_refresh_clicked)
        self._widget.commit_button.clicked[bool].connect(
            self._handle_commit_clicked)

        #self._widget.xdot_widget.connect(
        #self._widget.xdot_widget, SIGNAL('_update_graph'), self._widget.xdot_widget.set_dotcode)
        self.update_graph_sig.connect(self._update_graph)

        self.blocks = {}
        self.groups = {}

        self._ns = ""
        self._actions_connected = False
        self.enable_widgets(False)
        self.new_dotcode_data = ''

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(50)
        self.update_timer.timeout.connect(self._update_widgets)
        #self.update_timer.start()

        self._get_blocks = None
        self._set_blocks = None

        self._blocks_model = QStandardItemModel(0, 4)
        self._blocks_model.setHeaderData(0, Qt.Horizontal, "")
        self._blocks_model.setHeaderData(1, Qt.Horizontal, "Action")
        self._blocks_model.setHeaderData(2, Qt.Horizontal, "State")
        self._blocks_model.setHeaderData(3, Qt.Horizontal, "Block")
        self._widget.blocks_table.setModel(self._blocks_model)
        self._blocks_delegate = BlocksDelegate(self)
        self._widget.blocks_table.setItemDelegate(self._blocks_delegate)
        self._blocks_model.itemChanged.connect(self.block_changed)

        self._groups_model = QStandardItemModel(0, 4)
        self._groups_model.setHeaderData(0, Qt.Horizontal, "")
        self._groups_model.setHeaderData(1, Qt.Horizontal, "")
        self._groups_model.setHeaderData(2, Qt.Horizontal, "")
        self._groups_model.setHeaderData(3, Qt.Horizontal, "Group")
        self._widget.groups_table.setModel(self._groups_model)
        self._groups_delegate = GroupsDelegate(self)
        self._widget.groups_table.setItemDelegate(self._groups_delegate)

        self.refresh_combo_box()

    def block_changed(self, item):
        row = item.row()
        name = self._blocks_model.item(row, 3).text()
        block = self.blocks[name]
        checked = item.checkState() == Qt.Checked

    def shutdown_plugin(self):
        # TODO unregister all publishers here
        self._update_thread.kill()
        pass

    def save_settings(self, plugin_settings, instance_settings):
        # TODO save intrinsic configuration, usually using:
        # instance_settings.set_value(k, v)
        pass

    def restore_settings(self, plugin_settings, instance_settings):
        # TODO restore intrinsic configuration, usually using:
        # v = instance_settings.value(k)
        pass

    #def trigger_configuration(self):
    # Comment in to signal that the plugin has a way to configure
    # This will enable a setting button (gear icon) in each dock widget title bar
    # Usually used to open a modal configuration dialog

    @Slot()
    def refresh_combo_box(self):
        self._update_thread.kill()
        self._widget.namespace_input.setEnabled(False)
        self._widget.namespace_input.setEditText('updating...')
        self._update_thread.start()

    def _update_thread_run(self):
        _, _, topic_types = rospy.get_master().getTopicTypes()
        self._topic_dict = dict(topic_types)
        keys = list(self._topic_dict.keys())
        namespaces = list()
        for i in keys:
            if i.endswith("get_blocks_action/goal"):
                namespaces.append(i[0:i.index("get_blocks_action/goal")])

        self._widget.namespace_input.setItems.emit(namespaces)

    @Slot()
    def _update_finished(self):
        self._widget.namespace_input.setEnabled(True)

    def _get_result_cb(self, status, res):
        rospy.loginfo("got result!")
        self._blocks_model.setRowCount(0)
        self._blocks_model.setRowCount(len(res.blocks))

        for (i, block) in zip(range(len(res.blocks)), res.blocks):

            # Store in dict
            self.blocks[block.name] = block

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked if block.state.value == conman_msgs.
                             msg.TaskState.RUNNING else Qt.Unchecked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setTristate(True)

            action = QStandardItem(True)
            action.setText("")

            state = QStandardItem(True)
            state.setText(state_map[block.state.value])

            name = QStandardItem(True)
            name.setText(str(block.name))

            self._blocks_model.setItem(i, 0, cb)
            self._blocks_model.setItem(i, 1, action)
            self._blocks_model.setItem(i, 2, state)
            self._blocks_model.setItem(i, 3, name)

        for (i, group) in zip(range(len(res.groups)), res.groups):

            self.groups[group.name] = group

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setEnabled(False)

            name = QStandardItem(True)
            name.setText(str(group.name))

            self._groups_model.setItem(i, 0, cb)
            self._groups_model.setItem(i, 3, name)

        self._update_groups()
        self._update_blocks()

        self._widget.blocks_table.resizeColumnsToContents()
        self._widget.blocks_table.horizontalHeader().setStretchLastSection(
            True)
        self._widget.groups_table.resizeColumnsToContents()
        self._widget.groups_table.horizontalHeader().setStretchLastSection(
            True)

    def _update_blocks(self):

        for (name, block) in self.blocks.items():
            items = self._blocks_model.findItems(name, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue

            row = item.row()
            checked = self._blocks_model.item(row,
                                              0).checkState() == Qt.Checked
            if checked and block.state.value != conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row, 1).setText("ENABLE")
            elif not checked and block.state.value == conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row, 1).setText("DISABLE")
            else:
                self._blocks_model.item(row, 1).setText("")
        self._update_groups()

    def _enable_group(self, index, enable):
        name = self._groups_model.item(index, 3).text()
        group = self.groups[name]

        for member in group.members:
            items = self._blocks_model.findItems(member, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue

            row = item.row()
            self._blocks_model.item(
                row, 0).setCheckState(Qt.Checked if enable else Qt.Unchecked)

        self._update_blocks()

    def _update_groups(self):
        for (name, group) in self.groups.items():
            group_items = self._groups_model.findItems(name, column=3)
            if len(group_items) > 0:
                group_item = group_items[0]
            else:
                continue
            group_row = group_item.row()

            members_checked = []

            for member in group.members:
                items = self._blocks_model.findItems(member, column=3)
                if len(items) > 0:
                    item = items[0]
                else:
                    continue
                row = item.row()
                members_checked.append(
                    self._blocks_model.item(row, 0).checkState() == Qt.Checked)

            if all(members_checked):
                check = Qt.Checked
            else:
                check = Qt.Unchecked

            self._groups_model.item(group_row, 0).setCheckState(check)

    def _query_blocks(self):
        if self._get_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Getting blocks...")
                goal = conman_msgs.msg.GetBlocksGoal()
                goal.publish_flow_graph = self._widget.generate_graph_checkbox.isChecked(
                )
                self._get_blocks.send_goal(goal, done_cb=self._get_result_cb)

    def enable_widgets(self, enable):

        #self._widget.generate_graph_checkbox.setEnabled(enable)
        self._widget.force_enable_checkbox.setEnabled(enable)
        #self._widget.disable_unused_button.setEnabled(enable)
        self._widget.xdot_widget.setEnabled(enable)
        self._widget.blocks_table.setEnabled(enable)
        self._widget.groups_table.setEnabled(enable)
        self._widget.regenerate_graph_button.setEnabled(enable)

    def _handle_refresh_clicked(self, checked):
        ns = self._widget.namespace_input.currentText()

        if len(ns) > 0:
            if self._ns != ns:
                self._actions_connected = False
                self._ns = ns
                self.enable_widgets(False)

                self._dotcode_sub = rospy.Subscriber(ns + '/dotcode',
                                                     std_msgs.msg.String,
                                                     self._dotcode_msg_cb)

                self._get_blocks = actionlib.SimpleActionClient(
                    ns + '/get_blocks_action', conman_msgs.msg.GetBlocksAction)

                self._set_blocks = actionlib.SimpleActionClient(
                    ns + '/set_blocks_action', conman_msgs.msg.SetBlocksAction)

                rospy.loginfo("Creating action clients on namespace '%s'..." %
                              ns)

                if not self._get_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." %
                                  self._get_blocks.action_client.ns)
                    return
                if not self._set_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." %
                                  self._set_blocks.action_client.ns)
                    return

                rospy.loginfo("Action clients created.")
                self._actions_connected = True
                self.enable_widgets(True)

            self._query_blocks()

    def _handle_commit_clicked(self, checked):
        if self._set_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Setting blocks...")
                goal = conman_msgs.msg.SetBlocksGoal()
                goal.diff = True
                goal.force = True

                for i in range(self._blocks_model.rowCount()):
                    name = self._blocks_model.item(i, 3).text()
                    action = self._blocks_model.item(i, 1).text()

                    if action == 'DISABLE':
                        goal.disable.append(name)
                    elif action == 'ENABLE':
                        goal.enable.append(name)

                self._set_blocks.send_goal(goal,
                                           done_cb=self._get_set_result_cb)

    def _get_set_result_cb(self, status, res):

        self._query_blocks()

    @Slot(str)
    def _update_graph(self, dotcode):
        global initialized
        if initialized:
            self._widget.xdot_widget.set_dotcode(dotcode, center=False)
        else:
            self._widget.xdot_widget.set_dotcode(dotcode, center=True)
            self._widget.xdot_widget.zoom_to_fit()
            initialized = 1

    def _dotcode_msg_cb(self, msg):
        #self.new_dotcode_data = msg.data
        self.update_graph_sig.emit(msg.data)

    def _update_widgets(self):
        self._update_groups()
        self._update_blocks()
Esempio n. 4
0
class OutputDialog(QDialog):
    def __init__(self,
                 mode,
                 dotgraph,
                 dotcode_factory,
                 dotparser,
                 param_manager,
                 models_desc_file_path,
                 nodename='',
                 parent=None):
        super(OutputDialog, self).__init__(parent)

        if mode not in ['add', 'edit']:
            raise Exception('Wrong mode for Ouput Dialog')

        self.setWindowTitle("Add a output pipe")
        self.setGeometry(300, 300, 450, 250)

        # self._widget = QDialog()

        ui_file = os.path.join(rospkg.RosPack().get_path('rqt_vino_plugin'),
                               'resource', 'add_output_dialog.ui')
        loadUi(ui_file, self)

        self.dotgraph = dotgraph
        self.dotparser = dotparser
        self.dotcode_factory = dotcode_factory

        self.available_infers_list = param_manager.parse_inferlist_file(
            models_desc_file_path)

        self.connect_from_listmodel = QStandardItemModel()
        self.output_type_combobox.currentTextChanged.connect(
            self._update_display)
        self.update_output_types()

        if mode == 'add':
            self.buttonBox.accepted.connect(self._create_node_in_graph)
        elif mode == 'edit':
            self.nodename = nodename
            self.buttonBox.accepted.connect(self._edit_node_in_graph)

    def update_output_types(self, outputlist_file=None):
        self.output_type_combobox.clear()
        self.output_type_combobox.addItem('ImageWindow')
        self.output_type_combobox.addItem('Rviz')
        self.output_type_combobox.addItem('Rostopic')

    def get_infer_desc(self, infer_name):
        for infer in self.available_infers_list:
            if infer['infer_name'] == infer_name:
                return infer

    def _update_display(self, output_name):

        self.output_name_display_lineEdit.setText(output_name)
        self.update_connect_to_list(output_name)

    def update_connect_to_list(self, output_name):

        self.connect_from_listmodel.clear()

        for node in self.dotgraph.get_node_list():
            if node.get('nodetype') == 'input':
                pass
            elif node.get('nodetype') == 'output':
                pass
            elif node.get('nodetype') == 'infer':
                if output_name in self.get_infer_desc(
                        node.get_name())['connect_to']:

                    pipeline_item = QStandardItem()
                    pipeline_item.setText(node.get_name())
                    pipeline_item.setCheckable(True)
                    pipeline_item.setCheckState(False)

                    self.connect_from_listmodel.appendRow(pipeline_item)

        self.connect_from_listview.setModel(self.connect_from_listmodel)

    def _create_node_in_graph(self):

        output_node_name = str(self.output_type_combobox.currentText())

        #Create Node
        self.dotparser.parse_dotgraph_from_outputs(self.dotcode_factory,
                                                   self.dotgraph,
                                                   [output_node_name])

        #Create connection from input node to infer node
        for i in range(self.connect_from_listview.model().rowCount()):
            node_name = self.connect_from_listmodel.item(i).text()
            check_state = self.connect_from_listmodel.item(i).checkState()
            if check_state:
                connects = {node_name: [output_node_name]}
                self.dotparser.parse_dotgraph_from_connects(
                    self.dotcode_factory, self.dotgraph, connects)

    def _edit_node_in_graph(self):

        self.dotcode_factory.del_node_from_graph(self.dotgraph, self.nodename)
        self._create_node_in_graph()
Esempio n. 5
0
class Conman(Plugin):
    update_graph_sig = Signal(str)

    def __init__(self, context):
        super(Conman, self).__init__(context)

        self._dotcode_sub = None

        # Give QObjects reasonable names
        self.setObjectName('Conman')

        # 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 is a sibling of this file
        # in this example the .ui and .py file are in the same folder
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'rqt_conman.ui')
        # Extend the widget with all attributes and children from UI file
        loadUi(ui_file, self._widget)
        # Give QObjects reasonable names

        self._widget.setObjectName('ConmanPluginUi')
        # Show _widget.windowTitle on left-top of each plugin (when 
        # it's set in _widget). This is useful when you open multiple 
        # 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()))

        # Add widget to the user interface
        context.add_widget(self._widget)
        palette = QPalette ()
        palette.setColor(QPalette.Background, Qt.white)
        self._widget.setPalette(palette)

        #self._widget.subscribe_button.setCheckable(True)

        self._widget.refresh_button.clicked[bool].connect(self._handle_refresh_clicked)
        self._widget.commit_button.clicked[bool].connect(self._handle_commit_clicked)

        #self._widget.xdot_widget.connect(
                #self._widget.xdot_widget, SIGNAL('_update_graph'), self._widget.xdot_widget.set_dotcode)
        self.update_graph_sig.connect(self._update_graph)

        self.blocks = { }
        self.groups = { }

        self._ns = ""
        self._actions_connected = False
        self.enable_widgets(False)
        self.new_dotcode_data = ''

        self.update_timer = QTimer(self)
        self.update_timer.setInterval(50)
        self.update_timer.timeout.connect(self._update_widgets)
        #self.update_timer.start()


        self._get_blocks = None
        self._set_blocks = None

        self._blocks_model = QStandardItemModel(0,4)
        self._blocks_model.setHeaderData(0, Qt.Horizontal, "")
        self._blocks_model.setHeaderData(1, Qt.Horizontal, "Action")
        self._blocks_model.setHeaderData(2, Qt.Horizontal, "State")
        self._blocks_model.setHeaderData(3, Qt.Horizontal, "Block")
        self._widget.blocks_table.setModel(self._blocks_model)
        self._blocks_delegate = BlocksDelegate(self)
        self._widget.blocks_table.setItemDelegate(self._blocks_delegate)
        self._blocks_model.itemChanged.connect(self.block_changed)

        self._groups_model = QStandardItemModel(0,4)
        self._groups_model.setHeaderData(0, Qt.Horizontal, "")
        self._groups_model.setHeaderData(1, Qt.Horizontal, "")
        self._groups_model.setHeaderData(2, Qt.Horizontal, "")
        self._groups_model.setHeaderData(3, Qt.Horizontal, "Group")
        self._widget.groups_table.setModel(self._groups_model)
        self._groups_delegate = GroupsDelegate(self)
        self._widget.groups_table.setItemDelegate(self._groups_delegate)

    
    def block_changed(self, item):
        row = item.row()
        name = self._blocks_model.item(row,3).text()
        block = self.blocks[name]
        checked = item.checkState() == Qt.Checked

    def shutdown_plugin(self):
        # TODO unregister all publishers here
        pass

    def save_settings(self, plugin_settings, instance_settings):
        # TODO save intrinsic configuration, usually using:
        # instance_settings.set_value(k, v)
        pass

    def restore_settings(self, plugin_settings, instance_settings):
        # TODO restore intrinsic configuration, usually using:
        # v = instance_settings.value(k)
        pass

    #def trigger_configuration(self):
        # Comment in to signal that the plugin has a way to configure
        # This will enable a setting button (gear icon) in each dock widget title bar
        # Usually used to open a modal configuration dialog

    def _get_result_cb(self, status, res):
        rospy.loginfo("got result!")
        self._blocks_model.setRowCount(0)
        self._blocks_model.setRowCount(len(res.blocks))

        for (i,block) in zip(range(len(res.blocks)),res.blocks):

            # Store in dict
            self.blocks[block.name] = block

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked if block.state.value == conman_msgs.msg.TaskState.RUNNING else Qt.Unchecked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setTristate(True)

            action = QStandardItem(True)
            action.setText("")

            state = QStandardItem(True)
            state.setText(state_map[block.state.value])

            name = QStandardItem(True)
            name.setText(str(block.name))

            self._blocks_model.setItem(i,0,cb)
            self._blocks_model.setItem(i,1,action)
            self._blocks_model.setItem(i,2,state)
            self._blocks_model.setItem(i,3,name)

        for (i,group) in zip(range(len(res.groups)),res.groups):

            self.groups[group.name] = group

            cb = QStandardItem(True)
            cb.setCheckable(True)
            cb.setCheckState(Qt.Checked)
            cb.setTextAlignment(Qt.AlignHCenter)
            cb.setEnabled(False)

            name = QStandardItem(True)
            name.setText(str(group.name))

            self._groups_model.setItem(i,0,cb)
            self._groups_model.setItem(i,3,name)

        self._update_groups()
        self._update_blocks()

        self._widget.blocks_table.resizeColumnsToContents()
        self._widget.blocks_table.horizontalHeader().setStretchLastSection(True)
        self._widget.groups_table.resizeColumnsToContents()
        self._widget.groups_table.horizontalHeader().setStretchLastSection(True)

    def _update_blocks(self):
        
        for (name, block) in self.blocks.items():
            items = self._blocks_model.findItems(name, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue
            
            row = item.row()
            checked = self._blocks_model.item(row,0).checkState() == Qt.Checked
            if checked and block.state.value != conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row,1).setText("ENABLE")
            elif not checked and block.state.value == conman_msgs.msg.TaskState.RUNNING:
                self._blocks_model.item(row,1).setText("DISABLE")
            else:
                self._blocks_model.item(row,1).setText("")
        self._update_groups()

    def _enable_group(self, index, enable):
        name = self._groups_model.item(index, 3).text()
        group = self.groups[name]

        for member in group.members:
            items = self._blocks_model.findItems(member, column=3)
            if len(items) > 0:
                item = items[0]
            else:
                continue
            
            row = item.row()
            self._blocks_model.item(row,0).setCheckState(Qt.Checked if enable else Qt.Unchecked)

        self._update_blocks()
        
    def _update_groups(self):
        for (name, group) in self.groups.items():
            group_items = self._groups_model.findItems(name, column=3)
            if len(group_items) > 0:
                group_item = group_items[0]
            else:
                continue
            group_row = group_item.row()

            members_checked = []

            for member in group.members:
                items = self._blocks_model.findItems(member, column=3)
                if len(items) > 0:
                    item = items[0]
                else:
                    continue
                row = item.row()
                members_checked.append(self._blocks_model.item(row,0).checkState() == Qt.Checked)

            if all(members_checked):
                check = Qt.Checked
            else:
                check = Qt.Unchecked

            self._groups_model.item(group_row,0).setCheckState(check)


    def _query_blocks(self):
        if self._get_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Getting blocks...")
                goal = conman_msgs.msg.GetBlocksGoal()
                goal.publish_flow_graph = self._widget.generate_graph_checkbox.isChecked()
                self._get_blocks.send_goal(goal, done_cb=self._get_result_cb)


    def enable_widgets(self, enable):
        
        #self._widget.generate_graph_checkbox.setEnabled(enable)
        self._widget.force_enable_checkbox.setEnabled(enable)
        #self._widget.disable_unused_button.setEnabled(enable)
        self._widget.xdot_widget.setEnabled(enable)
        self._widget.blocks_table.setEnabled(enable)
        self._widget.groups_table.setEnabled(enable)
        self._widget.regenerate_graph_button.setEnabled(enable)

    def _handle_refresh_clicked(self, checked):
        ns = self._widget.namespace_input.text()

        if len(ns) > 0:
            if self._ns != ns:
                self._actions_connected = False
                self._ns = ns
                self.enable_widgets(False)

                self._dotcode_sub = rospy.Subscriber(
                        ns+'/dotcode',
                        std_msgs.msg.String,
                        self._dotcode_msg_cb)

                self._get_blocks = actionlib.SimpleActionClient(
                        ns+'/get_blocks_action',
                        conman_msgs.msg.GetBlocksAction)

                self._set_blocks = actionlib.SimpleActionClient(
                        ns+'/set_blocks_action',
                        conman_msgs.msg.SetBlocksAction)

                rospy.loginfo("Creating action clients on namespace '%s'..." % ns)

                if not self._get_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." % self._get_blocks.action_client.ns)
                    return
                if not self._set_blocks.wait_for_server(rospy.Duration(2)):
                    rospy.loginfo("Timed out waiting for %s." % self._set_blocks.action_client.ns)
                    return

                rospy.loginfo("Action clients created.")
                self._actions_connected = True
                self.enable_widgets(True)

            self._query_blocks()


    def _handle_commit_clicked(self, checked):
        if self._set_blocks and self._actions_connected:
            if self._get_blocks.simple_state == actionlib.SimpleGoalState.DONE:
                rospy.loginfo("Setting blocks...")
                goal = conman_msgs.msg.SetBlocksGoal()
                goal.diff = True
                goal.force = True

                for i in range(self._blocks_model.rowCount()):
                    name = self._blocks_model.item(i,3).text()
                    action = self._blocks_model.item(i,1).text()

                    if action == 'DISABLE':
                        goal.disable.append(name)
                    elif action == 'ENABLE':
                        goal.enable.append(name)

                self._set_blocks.send_goal(goal, done_cb=self._get_set_result_cb)

    def _get_set_result_cb(self, status, res):

        self._query_blocks()

    @Slot(str)
    def _update_graph(self,dotcode):
        self._widget.xdot_widget.set_dotcode(dotcode, center=False)

    def _dotcode_msg_cb(self, msg):
        #self.new_dotcode_data = msg.data
        self.update_graph_sig.emit(msg.data)
    
    def _update_widgets(self):
        self._update_groups()
        self._update_blocks()
class InferenceDialog(QDialog):
    def __init__(self, mode, dotgraph , dotcode_factory, dotparser , param_manager, models_desc_file_path, nodename='', parent = None):
        super(InferenceDialog, self).__init__(parent)



        if mode not in ['add','edit']:
            raise Exception('wrong mode for InferenceDialog')
        
    
        self.nodename = nodename

        self.setWindowTitle("Dialog")
        self.setGeometry(300,300,450,250)

        # self._widget = QDialog()

        ui_file = os.path.join(rospkg.RosPack().get_path('rqt_vino_plugin'), 'resource', 'add_inference_dialog.ui')
        loadUi(ui_file, self)
        

        self.dotgraph = dotgraph
        self.dotparser = dotparser
        self.dotcode_factory = dotcode_factory
 
 
        self.available_infers_list = param_manager.parse_inferlist_file(models_desc_file_path)
        


        # self.node_name_lineedit.textEdited.connect(self._edit_infer_name)
        #self.node_infer_name_combobox.activated.connect(self.update_infer_names)
        self.node_infer_combobox.currentTextChanged.connect(self._select_infer_type)

        self.connect_from_listmodel = QStandardItemModel()#(self.connect_from_listview)
        self.connect_to_listmodel = QStandardItemModel()#(self.connect_to_listview)

        # self.connect_from_listmodel.itemChanged.connect(self._connect_from_changed)
        
        #self.connect_to_listview.setModel(self.connect_to_listmodel)

      
        self.update_infer_names()
        self.update_connect_from_list()

        if mode == 'add':
            self.buttonBox.accepted.connect(self._create_node_in_graph)
        elif mode == 'edit':
            self.buttonBox.accepted.connect(self._edit_node_in_graph)
        

    def update_infer_names(self):
        self.node_infer_combobox.clear()
        for infer in self.available_infers_list:
            self.node_infer_combobox.addItem(infer['infer_name'])

    def get_infer_desc(self,infer_name):
        for infer in self.available_infers_list:
            if infer['infer_name'] == infer_name:
                return infer
    def get_model_desc(self,infer_name,model_type):
        for model_desc in self.get_infer_desc(infer_name)['available_models']:
            if model_desc['name'] == model_type:
                return model_desc
    def update_connect_to_list(self, infer_name):
        self.connect_from_listmodel.clear()
        self.connect_to_listmodel.clear()

        for node in self.dotgraph.get_node_list():
            
            pipeline_item = QStandardItem()
            pipeline_item.setText(node.get_name())
            pipeline_item.setCheckable(True)
            pipeline_item.setCheckState(False)

            if node.get_name() == infer_name.encode('utf-8'):
                continue
            if node.get('nodetype') == 'input':

                self.connect_from_listmodel.appendRow(pipeline_item)

                # self.connect_from_listview.addItem(node.get_name())
            elif node.get('nodetype') == 'output':
                self.connect_to_listmodel.appendRow(pipeline_item)
                # self.connect_to_listview.addItem(node.get_name())
            elif node.get('nodetype') == 'infer':
                if  infer_name in self.get_infer_desc(infer_name)['connect_from']:
                    self.connect_from_listmodel.appendRow(pipeline_item)
                elif  infer_name in self.get_infer_desc(infer_name)['connect_to']:
                    self.connect_to_listmodel.appendRow(pipeline_item)

            
        self.connect_from_listview.setModel(self.connect_from_listmodel)
        self.connect_to_listview.setModel(self.connect_to_listmodel)
   

    def update_connect_from_list(self):
        pass

    def update_model_type(self,infer_name):
        self.node_model_combobox.clear()
        # infer = self.get_infer_desc(infer_name)
        for model in self.get_infer_desc(infer_name)['available_models']:
            self.node_model_combobox.addItem(model['name'])
        # self.node_model_combobox.addItem("MobileNetSSD")
        # self.node_model_combobox.addItem("YoloV2")
    def _select_infer_type(self,infer_name):
        self.node_engine_combobox.clear()
        infer_name = str(infer_name)
        
        for infer in self.available_infers_list:
            if infer['infer_name'] == infer_name:
                for engine in infer['available_engine']:
                    self.node_engine_combobox.addItem(engine)

        self.update_model_type(infer_name)
        self.update_connect_to_list(infer_name)

    def _edit_infer_name(self,infer_name):
        self.node_name_display_lineEdit.setText(infer_name)

    
    def _create_node_in_graph(self):

        infer_node_name =  str(self.node_infer_combobox.currentText()) 
        print('ava_list',self.available_infers_list)

        infer_node_engine = self.node_engine_combobox.currentText()
        print(self.get_infer_desc(infer_node_name))
        infer_node_model_type = self.node_model_combobox.currentText()
        infer_node_label = self.get_model_desc(infer_node_name, infer_node_model_type)['label']
        infer_node_model = self.get_model_desc(infer_node_name, infer_node_model_type)['model']
        #Create Node 
        self.dotparser.parse_dotgraph_from_infers(self.dotcode_factory,self.dotgraph, [{'name': infer_node_name,
                                                                                        'engine':infer_node_engine,
                                                                                        'model':infer_node_model,
                                                                                        'label':infer_node_label,
                                                                                        'batch':1}])
                                                                                     #To-do Implement batch configure

        #Create connection from input node to infer node
        for i in range(self.connect_from_listview.model().rowCount()):
            node_name = self.connect_from_listmodel.item(i).text()
            check_state = self.connect_from_listmodel.item(i).checkState()
            if check_state:
                connects = { node_name: [infer_node_name] }
                self.dotparser.parse_dotgraph_from_connects(self.dotcode_factory,self.dotgraph,connects)
        
        #Create connection from infer node to output node
        for i in range(self.connect_to_listview.model().rowCount()):
            node_name = self.connect_to_listmodel.item(i).text()
            check_state = self.connect_to_listmodel.item(i).checkState()
            if check_state:
                connects = { infer_node_name :[node_name] }
                self.dotparser.parse_dotgraph_from_connects(self.dotcode_factory,self.dotgraph,connects)

                
    def _edit_node_in_graph(self):
       
        self.dotcode_factory.del_node_from_graph(self.dotgraph,self.nodename)
        self._create_node_in_graph()
Esempio n. 7
0
class InteractionsChooserUI():
    def __init__(self,
                 rocon_master_uri='localhost',
                 host_name='localhost',
                 with_rqt=False):
        self.with_rqt = with_rqt
        self.widget = QWidget()
        self.pairings_view_model = QStandardItemModel()
        self.interactions_view_model = QStandardItemModel()
        self.interactions_remocon = InteractionsRemocon(
            rocon_master_uri, host_name)
        self.interactions_remocon.connect(
            [self.update_group_combobox, self.refresh_grids])
        self.interactions_remocon.connect(
            [self.update_pairings_group_combobox, self.refresh_grids])
        self.default_group = "All"

        rospack = rospkg.RosPack()
        ui_file = os.path.join(rospack.get_path('rocon_remocon'), 'ui',
                               'interactions_chooser.ui')
        loadUi(ui_file, self.widget, {})

        # create a few directories for caching icons and ...
        utils.setup_home_dirs()
        self._init_ui()
        self._init_events()

    def shutdown(self):
        self.interactions_remocon.shutdown()

    @Slot()
    def update_group_combobox(self):
        """
        The underyling ros part of the remocon might get fresh data about the group list.
        Connect to this slot to update the combobox in the ui.
        """
        new_groups = copy.copy(
            self.interactions_remocon.interactions_table.groups())
        new_groups = [g for g in new_groups if g != "Hidden"]

        # did the underlying groups change - if so, update the combobox
        current_group = self.widget.interactions_group_combobox.currentText()
        current_size = self.widget.interactions_group_combobox.count()
        target_group = current_group if current_size != 1 else self.default_group
        current_group_list = [
            self.widget.interactions_group_combobox.itemText(i)
            for i in range(self.widget.interactions_group_combobox.count())
        ]
        if set(current_group_list) != set(['All'] + new_groups):
            self.widget.interactions_group_combobox.clear()
            self.widget.interactions_group_combobox.addItems(['All'] +
                                                             new_groups)
            index = self.widget.interactions_group_combobox.findText(
                target_group)
            if index != -1:
                self.widget.interactions_group_combobox.setCurrentIndex(index)
            self.refresh_grids()

    @Slot()
    def update_pairings_group_combobox(self):
        """
        The underyling ros part of the remocon might get fresh data about the group list.
        Connect to this slot to update the combobox in the ui.
        """
        new_groups = copy.copy(
            self.interactions_remocon.pairings_table.groups())

        # did the underlying groups change - if so, update the combobox
        current_group = self.widget.pairings_group_combobox.currentText()
        current_size = self.widget.pairings_group_combobox.count()
        target_group = current_group if current_size != 1 else self.default_pairings_group
        current_group_list = [
            self.widget.pairings_group_combobox.itemText(i)
            for i in range(self.widget.pairings_group_combobox.count())
        ]
        if set(current_group_list) != set(['All'] + new_groups):
            self.widget.pairings_group_combobox.clear()
            self.widget.pairings_group_combobox.addItems(['All'] + new_groups)
            index = self.widget.pairings_group_combobox.findText(target_group)
            if index != -1:
                self.widget.pairings_group_combobox.setCurrentIndex(index)
            self.refresh_grids()

    @Slot()
    def refresh_grids(self):
        """
        This just does a complete redraw of the interactions with the
        currently selected role. It's a bit brute force doing this
        every time the interactions' 'state' changes, but this suffices for now.
        """
        self.pairings_view_model.clear()
        self.interactions_view_model.clear()

        active_pairing = copy.copy(self.interactions_remocon.active_pairing)
        group = self.widget.pairings_group_combobox.currentText()
        for p in self.interactions_remocon.pairings_table.sorted():
            if group != "All" and p.group != group:
                continue
            is_running = False
            enabled = False
            if active_pairing is not None and p.name == active_pairing.name:
                is_running = True
                enabled = True
            elif active_pairing is None:
                enabled = True
                # enabled = not p.requires_interaction
            item = icon.QModelIconItem(p, enabled=enabled, running=is_running)
            self.pairings_view_model.appendRow(item)

        group = self.widget.interactions_group_combobox.currentText()
        for i in self.interactions_remocon.interactions_table.sorted():
            if group != "All" and i.group != group:
                continue
            if i.hidden:
                continue
            extra_tooltip_info = ""
            if i.required_pairings:
                extra_tooltip_info += " Requires "
                for required_pairing in i.required_pairings:
                    extra_tooltip_info += "'" + required_pairing + "', "
                extra_tooltip_info = extra_tooltip_info.rstrip(', ')
                if not i.bringup_pairing:
                    extra_tooltip_info += " to be running"
                extra_tooltip_info += "."
            item = icon.QModelIconItem(
                i,
                enabled=self._is_interaction_enabled(i),
                running=self._is_interaction_running(i),
                extended_tooltip_info=extra_tooltip_info)
            self.interactions_view_model.appendRow(item)

    def _init_ui(self):
        self.widget.pairings_grid.setViewMode(QListView.IconMode)
        self.widget.pairings_grid.setModel(self.pairings_view_model)
        self.widget.pairings_grid.setWordWrap(True)
        self.widget.pairings_grid.setWrapping(True)
        # really need to get away from listview, or subclass it if we want to control better how many lines of text show up
        # self.widget.pairings_grid.setTextElideMode(Qt.ElideNone)
        self.widget.pairings_grid.setIconSize(QSize(60, 60))
        self.widget.pairings_grid.setSpacing(10)
        self.widget.interactions_grid.setViewMode(QListView.IconMode)
        self.widget.interactions_grid.setModel(self.interactions_view_model)
        self.widget.interactions_grid.setWordWrap(True)
        self.widget.interactions_grid.setWrapping(True)
        self.widget.interactions_grid.setIconSize(QSize(60, 60))
        self.widget.interactions_grid.setSpacing(10)
        for ns in self.interactions_remocon.namespaces:
            self.widget.namespace_checkbox.addItem(ns)
        self.refresh_grids()
        self.widget.pairings_group_combobox.addItems(
            ['All'] + self.interactions_remocon.pairings_table.groups())
        self.widget.interactions_group_combobox.addItems(
            ['All'] + self.interactions_remocon.interactions_table.groups())
        # TODO namespace checkbox to self.interactions_remocon.active_namespace

    ##############################################################################
    # Private
    ##############################################################################

    def _init_events(self):
        self.widget.namespace_checkbox.currentIndexChanged.connect(
            self._event_change_namespace)
        self.widget.pairings_grid.clicked.connect(self._pairing_single_click)
        self.widget.interactions_grid.clicked.connect(
            self._interaction_single_click)
        self.widget.button_stop_all_interactions.clicked.connect(
            self.interactions_remocon.stop_all_interactions)
        self.widget.pairings_group_combobox.currentIndexChanged.connect(
            self.refresh_grids)
        self.widget.interactions_group_combobox.currentIndexChanged.connect(
            self.refresh_grids)

    def _event_change_namespace(self):
        rospy.logwarn(
            "Remocon : changing interaction managers is currently not supported."
        )

    def _pairing_single_click(self, index):
        pairing_item = self.pairings_view_model.item(index.row())
        pairing = pairing_item.implementation
        self._create_pairing_dialog(pairing)

    def _create_pairing_dialog(self, pairing):
        active_pairing = copy.copy(self.interactions_remocon.active_pairing)
        if active_pairing is not None:
            is_running = (active_pairing.name == pairing.name)
            is_enabled = is_running
        else:
            is_enabled = True  # not pairing.requires_interaction
            is_running = False
        self.selected_pairing = pairing
        self.dialog = PairingDialog(self.widget, pairing,
                                    self.interactions_remocon.start_pairing,
                                    self.interactions_remocon.stop_pairing,
                                    is_enabled, is_running)
        self.dialog.show()

    def _interaction_single_click(self, index):
        interaction_item = self.interactions_view_model.item(index.row())
        interaction = interaction_item.implementation
        self._create_interaction_dialog(interaction)

    def _create_interaction_dialog(self, interaction):
        self.selected_interaction = interaction
        self.dialog = InteractionDialog(
            self.widget, interaction,
            self.interactions_remocon.start_interaction,
            self.interactions_remocon.stop_interaction,
            self._is_interaction_enabled(interaction),
            self._is_interaction_running(interaction),
            self._is_interaction_permitted_new_launches(interaction))
        self.dialog.show()

    def _is_interaction_permitted_new_launches(self, interaction):
        current_number_of_launches = len(
            self.interactions_remocon.launched_interactions.get_launch_details(
                interaction.hash))
        if interaction.max == -1 or current_number_of_launches < interaction.max:
            return True
        else:
            return False

    def _is_interaction_enabled(self, interaction):
        active_pairing = copy.copy(self.interactions_remocon.active_pairing)
        enabled = True
        if interaction.required_pairings:
            if active_pairing and active_pairing.name not in interaction.required_pairings:
                enabled = False
            elif active_pairing is None:
                if not interaction.bringup_pairing:
                    enabled = False
                else:
                    available_required_pairings = [
                        name for name in interaction.required_pairings
                        if self.interactions_remocon.pairings_table.find(name)
                        is not None
                    ]
                    if not available_required_pairings:
                        enabled = False
        return enabled

    def _is_interaction_running(self, interaction):
        return True if self.interactions_remocon.launched_interactions.get_launch_details(
            interaction.hash) else False