def __init__(self, updater, config): super(EnumEditor, self).__init__(updater, config) loadUi(ui_enum, self) try: enum = eval(config['edit_method'])['enum'] except: # noqa: E722 logging.error('reconfig EnumEditor) Malformed enum') return # Setup the enum items self.names = [item['name'] for item in enum] self.values = [item['value'] for item in enum] items = [ '%s (%s)' % (self.names[i], self.values[i]) for i in range(0, len(self.names)) ] # Add items to the combo box self._combobox.addItems(items) # Initialize to the default self._combobox.setCurrentIndex(self.values.index(config['default'])) # Make selection update the param server self._combobox.currentIndexChanged['int'].connect(self.selected) # Make the param server update selection self._update_signal.connect(self._update_gui) # Bind the context menu self._combobox.contextMenuEvent = self.contextMenuEvent
def __init__(self, *args): """ :param args[0]: str (will become 1st arg of QStandardItem) :param args[1]: integer value that indicates whether this class is node that has GRN (Graph Resource Names, see http://www.ros.org/wiki/Names). This can be None """ grn_current_treenode = args[0] self._raw_param_name = grn_current_treenode self._set_param_name(grn_current_treenode) super(TreenodeQstdItem, self).__init__(grn_current_treenode) # dynamic_reconfigure.client.Client self._param_client = None # ParamClientWidget self._param_client_widget = None self._is_rosnode = False self._lock = threading.Lock() self._paramserver_connect_thread = None try: if args[1]: self._is_rosnode = True except IndexError: # tuple index out of range etc. logging.error('TreenodeQstdItem IndexError')
def selected(self, index): try: value = self.values[index] except IndexError: logging.error("Invalid selection '{}' for parameter '{}'".format( self._combobox.itemText(index), self.param_name)) else: self._update_paramserver(value)
def _update_nodetree_pernode(self): """ """ # TODO(Isaac): 11/25/2012 dynamic_reconfigure only returns params that # are associated with nodes. In order to handle independent # params, different approach needs taken. try: nodes = dyn_reconf.find_reconfigure_services() except rosservice.ROSServiceIOException as e: logging.error('Reconfigure GUI cannot connect to master.') raise e # TODO Make sure 'raise' here returns or finalizes func. if not nodes == self._nodes_previous: i_node_curr = 1 num_nodes = len(nodes) elapsedtime_overall = 0.0 for node_name_grn in nodes: # Skip this grn if we already have it if node_name_grn in self._nodeitems: i_node_curr += 1 continue time_siglenode_loop = time.time() # (Begin) For DEBUG ONLY; skip some dynreconf creation # if i_node_curr % 2 != 0: # i_node_curr += 1 # continue # (End) For DEBUG ONLY. #### # Instantiate QStandardItem. Inside, dyn_reconf client will # be generated too. treenodeitem_toplevel = TreenodeQstdItem( node_name_grn, TreenodeQstdItem.NODE_FULLPATH) _treenode_names = treenodeitem_toplevel.get_treenode_names() # Using OrderedDict here is a workaround for StdItemModel # not returning corresponding item to index. self._nodeitems[node_name_grn] = treenodeitem_toplevel self._add_children_treenode(treenodeitem_toplevel, self._rootitem, _treenode_names) time_siglenode_loop = time.time() - time_siglenode_loop elapsedtime_overall += time_siglenode_loop _str_progress = 'reconf ' + \ 'loading #{}/{} {} / {}sec node={}'.format( i_node_curr, num_nodes, round(time_siglenode_loop, 2), round(elapsedtime_overall, 2), node_name_grn ) # NOT a debug print - please DO NOT remove. This print works # as progress notification when loading takes long time. logging.debug(_str_progress) i_node_curr += 1
def _prune_nodetree_pernode(self): try: nodes = find_nodes_with_params(self._context.node) except Exception as e: logging.error('Reconfigure GUI cannot connect to master.') raise e # TODO Make sure 'raise' here returns or finalizes func. for i in reversed(range(0, self._rootitem.rowCount())): candidate_for_removal = \ self._rootitem.child(i).get_raw_param_name() if candidate_for_removal not in nodes: logging.debug( 'Removing {} because the server is no longer available.'. format(candidate_for_removal)) self._rootitem.removeRow(i) self._nodeitems.pop(candidate_for_removal).reset()
def _selection_changed_slot(self, selected, deselected): """ Send "open ROS Node box" signal. ONLY IF the selected treenode is the terminal treenode. Receives args from signal QItemSelectionModel.selectionChanged. :param selected: All indexs where selected (could be multiple) :type selected: QItemSelection :type deselected: QItemSelection """ # Getting the index where user just selected. Should be single. if not selected.indexes() and not deselected.indexes(): logging.error('Nothing selected? Not ideal to reach here') return index_current = None if selected.indexes(): index_current = selected.indexes()[0] elif len(deselected.indexes()) == 1: # Setting length criteria as 1 is only a workaround, to avoid # Node boxes on right-hand side disappears when filter key doesn't # match them. # Indeed this workaround leaves another issue. Question for # permanent solution is asked here http://goo.gl/V4DT1 index_current = deselected.indexes()[0] logging.debug(' - - - index_current={}'.format(index_current)) rosnode_name_selected = RqtRosGraph.get_upper_grn(index_current, '') # If retrieved node name isn't in the list of all nodes. if rosnode_name_selected not in self._nodeitems.keys(): # De-select the selected item. self.selectionModel.select(index_current, QItemSelectionModel.Deselect) return if selected.indexes(): try: self._selection_selected(index_current, rosnode_name_selected) except Exception as e: # TODO: print to sysmsg pane err_msg = 'Connection to node={} failed:\n{}'.format( rosnode_name_selected, e) import traceback traceback.print_exc() self._signal_msg.emit(err_msg) logging.error(err_msg) elif deselected.indexes(): try: self._selection_deselected(index_current, rosnode_name_selected) except Exception as e: self._signal_msg.emit(e) logging.error(e)
def connect_param_server(self): """ Connect to parameter server using dynamic_reconfigure client. Behavior is delegated to a private method _connect_param_server, and its return value, client, is set to member variable. @return void @raise ROSException: """ # If the treenode doesn't represent ROS Node, return None. with self._lock: if not self._is_rosnode: logging.error('connect_param_server failed due to missing ' 'ROS Node. Return with nothing.') return if not self._param_client: if self._paramserver_connect_thread: if self._paramserver_connect_thread.is_alive(): self._paramserver_connect_thread.join(1) self._paramserver_connect_thread = ParamserverConnectThread( self, self._raw_param_name) self._paramserver_connect_thread.start()