class ParameditWidget(QWidget):
    """
    This class represents a pane where parameter editor widgets of multiple
    nodes are shown. In rqt_reconfigure, this pane occupies right half of the
    entire visible area.
    """

    # public signal
    sig_node_disabled_selected = Signal(str)

    def __init__(self, rospack):
        """"""
        super(ParameditWidget, self).__init__()

        ui_file = os.path.join(rospack.get_path('rqt_reconfigure'),
                               'resource', 'paramedit_pane.ui')
        loadUi(ui_file, self, {'ParameditWidget': ParameditWidget})

        self._dynreconf_clients = OrderedDict()

        # Adding the list of Items
        self.vlayout = QVBoxLayout(self.scrollarea_holder_widget)

        #self._set_index_widgets(self.listview, paramitems_dict) # causes error
        self.destroyed.connect(self.close)

    def _set_index_widgets(self, view, paramitems_dict):
        """
        @deprecated: Causes error
        """
        i = 0
        for p in paramitems_dict:
            view.setIndexWidget(i, p)
            i += 1

    def show_reconf(self, dynreconf_widget):
        """
        Callback when user chooses a node.

        @param dynreconf_widget:
        """
        node_grn = dynreconf_widget.get_node_grn()
        rospy.logdebug('ParameditWidget.show str(node_grn)=%s', str(node_grn))

        dynreconf_client = None

        if not node_grn in self._dynreconf_clients.keys():
            # Add dynreconf widget if there hasn't one existed.

            #TODO think about sharing dynamic_reconfigure.client instances
            # with NodeSelecorWidget...generating 2 instances of the same node
            # is nothing but inefficient and bad design.

            try:
                dynreconf_client = dynamic_reconfigure.client.Client(
                                               str(node_grn), timeout=100.0)
            except rospy.exceptions.ROSException:
                rospy.logerr("Could not connect to %s" % node_grn)
                #TODO(Isaac) Needs to show err msg on GUI too.
                return

            _dynreconf_client = DynreconfClientWidget(dynreconf_client,
                                                      node_grn)
            # Client gets renewed every time different node_grn was clicked.

            self._dynreconf_clients.__setitem__(node_grn, _dynreconf_client)
            self.vlayout.addWidget(_dynreconf_client)
            _dynreconf_client.sig_node_disabled_selected.connect(
                                                           self._node_disabled)

        else:  # If there has one already existed, remove it.
            self._remove_node(node_grn)
            #LayoutUtil.clear_layout(self.vlayout)

            # Re-add the rest of existing items to layout.
            #for k, v in self._dynreconf_clients.iteritems():
            #    rospy.loginfo('added to layout k={} v={}'.format(k, v))
            #    self.vlayout.addWidget(v)

        # Add color to alternate the rim of the widget.
        LayoutUtil.alternate_color(self._dynreconf_clients.itervalues(),
                                   [Qt.white, Qt.lightGray])

    def close(self):
        for dc in self._dynreconf_clients:
            # Clear out the old widget
            dc.close()
            dc = None

            self._paramedit_scrollarea.deleteLater()

    def filter_param(self, filter_key):
        """
        :type filter_key:
        """

        #TODO Pick nodes that match filter_key.

        #TODO For the nodes that are kept in previous step, call
        #     DynreconfWidget.filter_param for all of its existing
        #     instances.
        pass

    def _remove_node(self, node_grn):
        try:
            i = self._dynreconf_clients.keys().index(node_grn)
        except ValueError:
            # ValueError occurring here means that the specified key is not
            # found, most likely already removed, which is possible in the
            # following situation/sequence:
            #
            # Node widget on ParameditWidget removed by clicking disable button
            # --> Node deselected on tree widget gets updated
            # --> Tree widget detects deselection
            # --> Tree widget emits deselection signal, which is captured by
            #     ParameditWidget's slot. Thus reaches this method again.
            return

        item = self.vlayout.itemAt(i)
        if isinstance(item, QWidgetItem):
                item.widget().close()
        w = self._dynreconf_clients.pop(node_grn)

        rospy.logdebug('popped={} Len of left clients={}'.format(
                                            w, len(self._dynreconf_clients)))

    def _node_disabled(self, node_grn):
        rospy.logdebug('paramedit_w _node_disabled grn={}'.format(node_grn))

        # Signal to notify other GUI components (eg. nodes tree pane) that
        # a node widget is disabled.
        self.sig_node_disabled_selected.emit(node_grn)

        # Remove the selected node widget from the internal list of nodes.
        self._remove_node(node_grn)
Ejemplo n.º 2
0
class ParameditWidget(QWidget):
    """
    This class represents a pane where parameter editor widgets of multiple
    nodes are shown. In rqt_reconfigure, this pane occupies right half of the
    entire visible area.
    """

    # public signal
    sig_node_disabled_selected = Signal(str)

    def __init__(self, rospack):
        """"""
        super(ParameditWidget, self).__init__()

        ui_file = os.path.join(rospack.get_path('rqt_reconfigure'), 'resource',
                               'paramedit_pane.ui')
        loadUi(ui_file, self, {'ParameditWidget': ParameditWidget})

        self._dynreconf_clients = OrderedDict()

        # Adding the list of Items
        self.vlayout = QVBoxLayout(self.scrollarea_holder_widget)

        #self._set_index_widgets(self.listview, paramitems_dict) # causes error
        self.destroyed.connect(self.close)

    def _set_index_widgets(self, view, paramitems_dict):
        """
        @deprecated: Causes error
        """
        i = 0
        for p in paramitems_dict:
            view.setIndexWidget(i, p)
            i += 1

    def show_reconf(self, dynreconf_widget):
        """
        Callback when user chooses a node.

        @param dynreconf_widget:
        """
        node_grn = dynreconf_widget.get_node_grn()
        rospy.logdebug('ParameditWidget.show str(node_grn)=%s', str(node_grn))

        dynreconf_client = None

        if not node_grn in self._dynreconf_clients.keys():
            # Add dynreconf widget if there hasn't one existed.

            #TODO think about sharing dynamic_reconfigure.client instances
            # with NodeSelecorWidget...generating 2 instances of the same node
            # is nothing but inefficient and bad design.

            try:
                dynreconf_client = dynamic_reconfigure.client.Client(
                    str(node_grn), timeout=5.0)
            except rospy.exceptions.ROSException:
                rospy.logerr("Could not connect to %s" % node_grn)
                #TODO(Isaac) Needs to show err msg on GUI too.
                return

            _dynreconf_client = DynreconfClientWidget(dynreconf_client,
                                                      node_grn)
            # Client gets renewed every time different node_grn was clicked.

            self._dynreconf_clients.__setitem__(node_grn, _dynreconf_client)
            self.vlayout.addWidget(_dynreconf_client)
            _dynreconf_client.sig_node_disabled_selected.connect(
                self._node_disabled)

        else:  # If there has one already existed, remove it.
            self._remove_node(node_grn)
            #LayoutUtil.clear_layout(self.vlayout)

            # Re-add the rest of existing items to layout.
            #for k, v in self._dynreconf_clients.iteritems():
            #    rospy.loginfo('added to layout k={} v={}'.format(k, v))
            #    self.vlayout.addWidget(v)

        # Add color to alternate the rim of the widget.
        LayoutUtil.alternate_color(self._dynreconf_clients.itervalues(),
                                   [Qt.white, Qt.lightGray])

    def close(self):
        for dc in self._dynreconf_clients:
            # Clear out the old widget
            dc.close()
            dc = None

            self._paramedit_scrollarea.deleteLater()

    def filter_param(self, filter_key):
        """
        :type filter_key:
        """

        #TODO Pick nodes that match filter_key.

        #TODO For the nodes that are kept in previous step, call
        #     DynreconfWidget.filter_param for all of its existing
        #     instances.
        pass

    def _remove_node(self, node_grn):
        try:
            i = self._dynreconf_clients.keys().index(node_grn)
        except ValueError:
            # ValueError occurring here means that the specified key is not
            # found, most likely already removed, which is possible in the
            # following situation/sequence:
            #
            # Node widget on ParameditWidget removed by clicking disable button
            # --> Node deselected on tree widget gets updated
            # --> Tree widget detects deselection
            # --> Tree widget emits deselection signal, which is captured by
            #     ParameditWidget's slot. Thus reaches this method again.
            return

        item = self.vlayout.itemAt(i)
        if isinstance(item, QWidgetItem):
            item.widget().close()
        w = self._dynreconf_clients.pop(node_grn)

        rospy.logdebug('popped={} Len of left clients={}'.format(
            w, len(self._dynreconf_clients)))

    def _node_disabled(self, node_grn):
        rospy.logdebug('paramedit_w _node_disabled grn={}'.format(node_grn))

        # Signal to notify other GUI components (eg. nodes tree pane) that
        # a node widget is disabled.
        self.sig_node_disabled_selected.emit(node_grn)

        # Remove the selected node widget from the internal list of nodes.
        self._remove_node(node_grn)