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)
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)