def on_ctrl_list_tree_widget_customContextMenuRequested(self, pos): ctrlman_ns = self.cm_namespace_combo.currentText() item = self.ctrl_list_tree_widget.itemAt(pos) if item is None: return ctrl_name = item.data(0, Qt.UserRole) ctrl_state = self._ctrlers[ctrl_name]['state'] # show context menu menu = QMenu(self) if ctrl_state == 'running': action_stop = menu.addAction( QIcon.fromTheme('media-playback-stop'), 'Stop Controller') action_kill = menu.addAction( QIcon.fromTheme('list-remove'), 'Stop and Unload Controller') elif ctrl_state == 'stopped': action_start = menu.addAction( QIcon.fromTheme('media-playback-start'), 'Start Controller') action_unload = menu.addAction( QIcon.fromTheme('list-remove'), 'Unload Controller') action = menu.exec_(self.ctrl_list_tree_widget.mapToGlobal(pos)) # evaluate user action if ctrl_state == 'running': if action is action_stop: self.start_stop_controller(ctrlman_ns, ctrl_name, False) elif action is action_kill: self.start_stop_controller(ctrlman_ns, ctrl_name, False) self.unload_controller(ctrlman_ns, ctrl_name) elif ctrl_state == 'stopped': if action is action_start: self.start_stop_controller(ctrlman_ns, ctrl_name, True) elif action is action_unload: self.unload_controller(ctrlman_ns, ctrl_name)
def handle_header_view_customContextMenuRequested(self, pos): # create context menu menu = QMenu(self) action_toggle_auto_resize = menu.addAction('Auto-Resize') action_toggle_auto_resize.setCheckable(True) auto_resize_flag = (self.header().resizeMode(0) == QHeaderView.ResizeToContents) action_toggle_auto_resize.setChecked(auto_resize_flag) action_toggle_sorting = menu.addAction('Sorting') action_toggle_sorting.setCheckable(True) action_toggle_sorting.setChecked(self.isSortingEnabled()) # show menu action = menu.exec_(self.header().mapToGlobal(pos)) # evaluate user action if action is action_toggle_auto_resize: if auto_resize_flag: self.header().setResizeMode(QHeaderView.Interactive) else: self.header().setResizeMode(QHeaderView.ResizeToContents) elif action is action_toggle_sorting: self.setSortingEnabled(not self.isSortingEnabled())
def glview_mouseReleaseEvent(self, event): if event.button() == Qt.RightButton: menu = QMenu(self._glview) action = QAction(self._glview.tr("Reset view"), self._glview) menu.addAction(action) action.triggered.connect(self.set_default_view) menu.exec_(self._glview.mapToGlobal(event.pos()))
def _create_context_menu_for_tag(self): if isinstance(self.hl, XmlHighlighter): tag = self.hl.get_tag_of_current_block(self.textCursor().block(), self.textCursor().positionInBlock()) if tag: try: menu = QMenu("ROS <%s>" % tag, self) menu.triggered.connect(self._context_activated) # create a menu with attributes if tag in XmlHighlighter.LAUNCH_ATTR: menu_attr = QMenu("attributes", menu) attributes = sorted(list(set(XmlHighlighter.LAUNCH_ATTR[tag]))) for attr in attributes: action = menu_attr.addAction(attr.rstrip('=')) action.setData('%s""' % attr) menu.addMenu(menu_attr) # create a menu with tags if tag in XmlHighlighter.LAUNCH_CHILDS: tags = sorted(XmlHighlighter.LAUNCH_CHILDS[tag]) if tags: menu_tags = QMenu("tags", menu) for tag in tags: data = '<%s></%s>' % (tag, tag) if XmlHighlighter.LAUNCH_CHILDS[tag] else '<%s/>' % tag action = menu_tags.addAction(tag) action.setData(data) menu.addMenu(menu_tags) return menu except Exception: print(traceback.format_exc(1)) return None return None
def _create_context_menu_for_tag(self): if isinstance(self.hl, XmlHighlighter): tag = self.hl.get_tag_of_current_block(self.textCursor().block(), self.textCursor().positionInBlock()) if tag: try: menu = QMenu("ROS <%s>" % tag, self) menu.triggered.connect(self._context_activated) # create a menu with attributes menu_attr = QMenu("attributes", menu) attributes = sorted(list(set(XmlHighlighter.LAUNCH_ATTR[tag]))) for attr in attributes: action = menu_attr.addAction(attr.rstrip('=')) action.setData('%s""' % attr) menu.addMenu(menu_attr) # create a menu with tags tags = sorted(XmlHighlighter.LAUNCH_CHILDS[tag]) if tags: menu_tags = QMenu("tags", menu) for tag in tags: data = '<%s></%s>' % (tag, tag) if XmlHighlighter.LAUNCH_CHILDS[tag] else '<%s/>' % tag action = menu_tags.addAction(tag) action.setData(data) menu.addMenu(menu_tags) return menu except: import traceback print traceback.format_exc(1) return None return None
def _add_highlight_filter(self, filter_index=False): """ :param filter_index: if false then this function shows a QMenu to allow the user to choose a type of message filter. ''bool'' OR :param filter_index: the index of the filter to be added, ''int'' :return: if a filter was added then the index is returned, ''int'' OR :return: if no filter was added then None is returned, ''NoneType'' """ if filter_index is False: filter_index = -1 filter_select_menu = QMenu() for index in self._filter_factory_order: # flattens the _highlight filters list and only adds the item if it doesn't already exist if index in ['message', 'location'] or \ not self.filter_factory[index][1] in \ [type(item)for sublist in self._highlight_filters for item in sublist]: filter_select_menu.addAction(self.filter_factory[index][0]) action = filter_select_menu.exec_(QCursor.pos()) if action is None: return for index in self._filter_factory_order: if self.filter_factory[index][0] == action.text(): filter_index = index if filter_index == -1: return index = len(self._highlight_filters) newfilter = self.filter_factory[filter_index][1]() if len(self.filter_factory[filter_index]) >= 4: newwidget = self.filter_factory[filter_index][2]( newfilter, self._rospack, self.filter_factory[filter_index][3]) else: newwidget = self.filter_factory[filter_index][2](newfilter, self._rospack) # pack the new filter tuple onto the filter list self._highlight_filters.append( (newfilter, FilterWrapperWidget(newwidget, self.filter_factory[filter_index][0]), filter_index)) self._proxy_model.add_highlight_filter(newfilter) newfilter.filter_changed_signal.connect( self._proxy_model.handle_highlight_filters_changed) self._highlight_filters[index][1].delete_button.clicked.connect( self._delete_highlight_filter) self._model.rowsInserted.connect( self._highlight_filters[index][1].repopulate) # place the widget in the proper location self.highlight_table.insertRow(index) self.highlight_table.setCellWidget(index, 0, self._highlight_filters[index][1]) self.highlight_table.resizeColumnsToContents() self.highlight_table.resizeRowsToContents() newfilter.filter_changed_signal.emit() return index
def contextMenuEvent(self, event): menu = QMenu() clip = menu.addAction('clip') clip.setEnabled(False) menu.addSeparator() remove = menu.addAction('remove clip') result = menu.exec_(event.screenPos()) if result == remove: self.scene().removeItem(self)
def _rightclick_menu(self, event): """ :type event: QEvent """ # QTreeview.selectedIndexes() returns 0 when no node is selected. # This can happen when after booting no left-click has been made yet # (ie. looks like right-click doesn't count). These lines are the # workaround for that problem. selected = self._messages_tree.selectedIndexes() if len(selected) == 0: return menu = QMenu() text_action = QAction(self.tr('View Text'), menu) menu.addAction(text_action) raw_action = QAction(self.tr('View Raw'), menu) menu.addAction(raw_action) action = menu.exec_(event.globalPos()) if action == raw_action or action == text_action: rospy.logdebug('_rightclick_menu selected={}'.format(selected)) selected_type = selected[1].data() if selected_type[-2:] == '[]': selected_type = selected_type[:-2] browsetext = None try: if (self._mode == rosmsg.MODE_MSG or self._mode == rosaction.MODE_ACTION): browsetext = rosmsg.get_msg_text(selected_type, action == raw_action) elif self._mode == rosmsg.MODE_SRV: browsetext = rosmsg.get_srv_text(selected_type, action == raw_action) else: raise except rosmsg.ROSMsgException, e: QMessageBox.warning( self, self.tr('Warning'), self.tr('The selected item component ' + 'does not have text to view.')) if browsetext is not None: self._browsers.append( TextBrowseDialog(browsetext, self._rospack)) self._browsers[-1].show()
def context_menu_request(self, point): if self.selectionModel().hasSelection(): menu = QMenu(self) menu.addAction(self._action_item_add) menu.addAction(self._action_item_remove) menu.addSeparator() menu.addAction(self._action_item_expand) menu.addAction(self._action_item_collapse) menu.exec_(self.mapToGlobal(point))
def __init__(self, parent=None): ''' Creates the window, connects the signals and init the class. ''' QDockWidget.__init__(self, parent) # initialize parameter self.__current_path = os.path.expanduser('~') # load the UI file ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'LaunchFilesDockWidget.ui') loadUi(ui_file, self) # initialize the view for the launch files self.launchlist_model = LaunchListModel() self.launchlist_proxyModel = QSortFilterProxyModel(self) self.launchlist_proxyModel.setSourceModel(self.launchlist_model) self.xmlFileView.setModel(self.launchlist_proxyModel) self.xmlFileView.setAlternatingRowColors(True) self.xmlFileView.activated.connect(self.on_launch_selection_activated) self.xmlFileView.setDragDropMode(QAbstractItemView.DragOnly) self.xmlFileView.setDragEnabled(True) sm = self.xmlFileView.selectionModel() sm.selectionChanged.connect(self.on_xmlFileView_selection_changed) # self.searchPackageLine.setVisible(False) self.searchPackageLine.textChanged.connect(self.set_package_filter) self.searchPackageLine.focusInEvent = self._searchline_focusInEvent # connect to the button signals self.refreshXmlButton.clicked.connect(self.on_refresh_xml_clicked) self.editXmlButton.clicked.connect(self.on_edit_xml_clicked) self.newXmlButton.clicked.connect(self.on_new_xml_clicked) self.openXmlButton.clicked.connect(self.on_open_xml_clicked) self.transferButton.clicked.connect(self.on_transfer_file_clicked) self.loadXmlButton.clicked.connect(self.on_load_xml_clicked) self.loadXmlAsDefaultButton.clicked.connect(self.on_load_as_default) # creates a default config menu start_menu = QMenu(self) self.loadDeafaultAtHostAct = QAction( "&Load default config on host", self, statusTip="Loads the default config at given host", triggered=self.on_load_as_default_at_host) start_menu.addAction(self.loadDeafaultAtHostAct) self.loadXmlAsDefaultButton.setMenu(start_menu) # initialize the progress queue self.progress_queue = ProgressQueue(self.progressFrame_cfg, self.progressBar_cfg, self.progressCancelButton_cfg, 'Launch File')
def _rightclick_menu(self, event): """ :type event: QEvent """ # QTreeview.selectedIndexes() returns 0 when no node is selected. # This can happen when after booting no left-click has been made yet # (ie. looks like right-click doesn't count). These lines are the # workaround for that problem. selected = self._messages_tree.selectedIndexes() if len(selected) == 0: return menu = QMenu() text_action = QAction(self.tr('View Text'), menu) menu.addAction(text_action) raw_action = QAction(self.tr('View Raw'), menu) menu.addAction(raw_action) action = menu.exec_(event.globalPos()) if action == raw_action or action == text_action: rospy.logdebug('_rightclick_menu selected={}'.format(selected)) selected_type = selected[1].data() if selected_type[-2:] == '[]': selected_type = selected_type[:-2] browsetext = None try: if (self._mode == rosmsg.MODE_MSG or self._mode == rosaction.MODE_ACTION): browsetext = rosmsg.get_msg_text(selected_type, action == raw_action) elif self._mode == rosmsg.MODE_SRV: browsetext = rosmsg.get_srv_text(selected_type, action == raw_action) else: raise except rosmsg.ROSMsgException, e: QMessageBox.warning(self, self.tr('Warning'), self.tr('The selected item component ' + 'does not have text to view.')) if browsetext is not None: self._browsers.append(TextBrowseDialog(browsetext, self._rospack)) self._browsers[-1].show()
def _add_exclude_filter(self, filter_index=False): """ :param filter_index: if false then this function shows a QMenu to allow the user to choose a type of message filter. ''bool'' OR :param filter_index: the index of the filter to be added, ''int'' :return: if a filter was added then the index is returned, ''int'' OR :return: if no filter was added then None is returned, ''NoneType'' """ if filter_index is False: filter_index = -1 filter_select_menu = QMenu() for index in self._filter_factory_order: # flattens the _exclude filters list and only adds the item if it doesn't already exist if index in ['message', 'location'] or not self.filter_factory[index][1] in [type(item) for sublist in self._exclude_filters for item in sublist]: filter_select_menu.addAction(self.filter_factory[index][0]) action = filter_select_menu.exec_(QCursor.pos()) if action is None: return None for index in self._filter_factory_order: if self.filter_factory[index][0] == action.text(): filter_index = index if filter_index == -1: return None index = len(self._exclude_filters) newfilter = self.filter_factory[filter_index][1]() if len(self.filter_factory[filter_index]) >= 4: newwidget = self.filter_factory[filter_index][2](newfilter, self._rospack, self.filter_factory[filter_index][3]) else: newwidget = self.filter_factory[filter_index][2](newfilter, self._rospack) # pack the new filter tuple onto the filter list self._exclude_filters.append((newfilter, FilterWrapperWidget(newwidget, self.filter_factory[filter_index][0]), filter_index)) self._proxy_model.add_exclude_filter(newfilter) newfilter.filter_changed_signal.connect(self._proxy_model.handle_exclude_filters_changed) self._exclude_filters[index][1].delete_button.clicked.connect(self._delete_exclude_filter) self._model.rowsInserted.connect(self._exclude_filters[index][1].repopulate) # place the widget in the proper location self.exclude_table.insertRow(index) self.exclude_table.setCellWidget(index, 0, self._exclude_filters[index][1]) self.exclude_table.resizeColumnsToContents() self.exclude_table.resizeRowsToContents() newfilter.filter_changed_signal.emit() return index
def _show_context_menu(self, item, global_pos): if item is None: return # show context menu menu = QMenu(self) action_item_expand = menu.addAction(QIcon.fromTheme('zoom-in'), "Expand All Children") action_item_collapse = menu.addAction(QIcon.fromTheme('zoom-out'), "Collapse All Children") action = menu.exec_(global_pos) # evaluate user action if action in (action_item_expand, action_item_collapse): expanded = (action is action_item_expand) def recursive_set_expanded(item): item.setExpanded(expanded) for index in range(item.childCount()): recursive_set_expanded(item.child(index)) recursive_set_expanded(item)
def contextMenuEvent(self, event): menu = QMenu() clip = menu.addAction('track') clip.setEnabled(False) menu.addSeparator() copy_to = {} for destination_track in self.scene().tracks(self._type): if destination_track is not self: copy_to[menu.addAction('copy track to "%s"' % destination_track.name())] = destination_track clear = menu.addAction('clear track') result = menu.exec_(event.screenPos()) if result == clear: self.clear() elif result in copy_to: destination_track = copy_to[result] destination_track.clear() for clip in self.clips(): destination_track.add_clip(clip.text(), clip.starttime(), clip.duration(), clip.data())
def on_topics_tree_widget_customContextMenuRequested(self, pos): item = self.topics_tree_widget.itemAt(pos) if item is None: return # show context menu menu = QMenu(self) action_item_expand = menu.addAction(QIcon.fromTheme('zoom-in'), 'Expand All Children') action_item_collapse = menu.addAction(QIcon.fromTheme('zoom-out'), 'Collapse All Children') action = menu.exec_(self.topics_tree_widget.mapToGlobal(pos)) # evaluate user action if action in (action_item_expand, action_item_collapse): expanded = (action is action_item_expand) def recursive_set_expanded(item): item.setExpanded(expanded) for index in range(item.childCount()): recursive_set_expanded(item.child(index)) recursive_set_expanded(item)
def positions_list_context_menu(self, group_type, pos): list_widget = self.list_widgets[group_type] list_item = list_widget.itemAt(pos) if list_item is None: return menu = QMenu() move_to = {} for group in self.robot_config.group_list(): if list_item._type == group.group_type: move_to[menu.addAction('move "%s"' % group.name)] = [group.name] # move_to[menu.addAction('move all')] = list(move_to.itervalues()) move_to[menu.addAction('move all')] = [group_list[0] for group_list in list(move_to.itervalues())] result = menu.exec_(list_widget.mapToGlobal(pos)) if result in move_to: group_names = move_to[result] for group_name in group_names: target_positions = self.robot_config.groups[group_name].adapt_to_side(list_item._data) self._motion_publisher.move_to_position(group_name, target_positions, self.time_factor_spin.value()) print '[Motion Editor] Moving %s to: %s' % (group_name, zip(self.robot_config.groups[group_name].joints_sorted(), target_positions))
def _open_context_menu(self, position): indexes = self.plugin_manager_widget.plugin_tree_view.selectedIndexes() level = -1 if len(indexes) > 0: level = 0 index = indexes[0] while index.parent().isValid(): index = index.parent() level += 1 menu = QMenu() if level == 0: expand_action = QAction(self.tr('Expand'), None) expand_action.triggered.connect(self.plugin_manager_widget.plugin_tree_view.expandAll) menu.addAction(expand_action) if level == 0 or level == 1: remove_action = QAction(self.tr('Remove'), None) remove_action.triggered.connect(self.remove_plugins) menu.addAction(remove_action) menu.exec_(self.plugin_manager_widget.plugin_tree_view.viewport().mapToGlobal(position))
def __init__(self, parent=None): ''' Creates the window, connects the signals and init the class. ''' QDockWidget.__init__(self, parent) # initialize parameter self.__current_path = os.path.expanduser('~') # load the UI file ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'LaunchFilesDockWidget.ui') loadUi(ui_file, self) # initialize the view for the launch files self.launchlist_model = LaunchListModel() self.launchlist_proxyModel = QSortFilterProxyModel(self) self.launchlist_proxyModel.setSourceModel(self.launchlist_model) self.xmlFileView.setModel(self.launchlist_proxyModel) self.xmlFileView.setAlternatingRowColors(True) self.xmlFileView.activated.connect(self.on_launch_selection_activated) self.xmlFileView.setDragDropMode(QAbstractItemView.DragOnly) self.xmlFileView.setDragEnabled(True) sm = self.xmlFileView.selectionModel() sm.selectionChanged.connect(self.on_xmlFileView_selection_changed) # self.searchPackageLine.setVisible(False) self.searchPackageLine.textChanged.connect(self.set_package_filter) self.searchPackageLine.focusInEvent = self._searchline_focusInEvent # connect to the button signals self.refreshXmlButton.clicked.connect(self.on_refresh_xml_clicked) self.editXmlButton.clicked.connect(self.on_edit_xml_clicked) self.newXmlButton.clicked.connect(self.on_new_xml_clicked) self.openXmlButton.clicked.connect(self.on_open_xml_clicked) self.transferButton.clicked.connect(self.on_transfer_file_clicked) self.loadXmlButton.clicked.connect(self.on_load_xml_clicked) self.loadXmlAsDefaultButton.clicked.connect(self.on_load_as_default) # creates a default config menu start_menu = QMenu(self) self.loadDeafaultAtHostAct = QAction("&Load default config on host", self, statusTip="Loads the default config at given host", triggered=self.on_load_as_default_at_host) start_menu.addAction(self.loadDeafaultAtHostAct) self.loadXmlAsDefaultButton.setMenu(start_menu) # initialize the progress queue self.progress_queue = ProgressQueue(self.progressFrame_cfg, self.progressBar_cfg, self.progressCancelButton_cfg)
def _on_header_menu(self, pos): header = self._widget.table_view.horizontalHeader() # Show context menu menu = QMenu(self._widget.table_view) action_toggle_auto_resize = menu.addAction('Toggle Auto-Resize') action = menu.exec_(header.mapToGlobal(pos)) # Evaluate user action if action is action_toggle_auto_resize: if header.resizeMode(0) == QHeaderView.ResizeToContents: header.setResizeMode(QHeaderView.Interactive) else: header.setResizeMode(QHeaderView.ResizeToContents)
def handle_header_view_customContextMenuRequested(self, pos): header = self.topics_tree_widget.header() # show context menu menu = QMenu(self) action_toggle_auto_resize = menu.addAction('Toggle Auto-Resize') action = menu.exec_(header.mapToGlobal(pos)) # evaluate user action if action is action_toggle_auto_resize: if header.resizeMode(0) == QHeaderView.ResizeToContents: header.setResizeMode(QHeaderView.Interactive) else: header.setResizeMode(QHeaderView.ResizeToContents)
def eventFilter(self, obj, event): if event.type() in self._event_callbacks: ret_val = self._event_callbacks[event.type()](obj, event) if ret_val is not None: return ret_val if event.type() == event.ContextMenu and obj == self.title_label: menu = QMenu(self) rename_action = menu.addAction(self.tr('Rename dock widget')) hide_action = QAction("Hide title bar", self) hide_action.setCheckable(True) hide_action.setChecked(self.hide_title_bar) if self._dock_widget.features() & QDockWidget.DockWidgetFloatable and \ self._dock_widget.features() & QDockWidget.DockWidgetMovable: menu.addAction(hide_action) action = menu.exec_(self.mapToGlobal(event.pos())) if action == rename_action: self.title_label.hide() self.title_edit.setText(self.title_label.text()) self.title_edit.show() self.title_edit.setFocus() if action == hide_action: self.hide_title_bar = not self.hide_title_bar return True return QObject.eventFilter(self, obj, event)
def _open_context_menu(self, position): indexes = self.plugin_manager_widget.plugin_tree_view.selectedIndexes() level = -1 if len(indexes) > 0: level = 0 index = indexes[0] while index.parent().isValid(): index = index.parent() level += 1 menu = QMenu() if level == 0: expand_action = QAction(self.tr('Expand'), None) expand_action.triggered.connect( self.plugin_manager_widget.plugin_tree_view.expandAll) menu.addAction(expand_action) if level == 0 or level == 1: remove_action = QAction(self.tr('Remove'), None) remove_action.triggered.connect(self.remove_plugins) menu.addAction(remove_action) menu.exec_( self.plugin_manager_widget.plugin_tree_view.viewport().mapToGlobal( position))
def eventFilter(self, obj, event): if event.type() in self._event_callbacks: ret_val = self._event_callbacks[event.type()](obj, event) if ret_val is not None: return ret_val if event.type() == event.ContextMenu and obj == self.title_label: menu = QMenu(self) rename_action = menu.addAction(self.tr('Rename dock widget')) action = menu.exec_(self.mapToGlobal(event.pos())) if action == rename_action: self.title_label.hide() self.title_edit.setText(self.title_label.text()) self.title_edit.show() self.title_edit.setFocus() return True return QObject.eventFilter(self, obj, event)
def _create_context_substitution_menu(self, force_all=True): if isinstance(self.hl, XmlHighlighter): text = self.toPlainText() pos = self.textCursor().position() - 1 try: if force_all or (text[pos] == '$' or (text[pos] == '(' and text[pos - 1] == '$')): menu = QMenu("ROS substitution args", self) menu.triggered.connect(self._context_activated) for arg in self.SUBSTITUTION_ARGS: action = menu.addAction("%s" % arg) if force_all: action.setData("$(%s )" % arg) else: action.setData("(%s" % arg if text[pos] == '$' else "%s" % arg) return menu except Exception: pass return None
def _create_context_substitution_menu(self, force_all=True): if isinstance(self.hl, XmlHighlighter): text = self.toPlainText() pos = self.textCursor().position() - 1 try: if force_all or (text[pos] == '$' or (text[pos] == '(' and text[pos - 1] == '$')): menu = QMenu("ROS substitution args", self) menu.triggered.connect(self._context_activated) for arg in self.SUBSTITUTION_ARGS: action = menu.addAction("%s" % arg) if force_all: action.setData("$(%s )" % arg) else: action.setData("(%s" % arg if text[pos] == '$' else "%s" % arg) return menu except: pass return None
def _on_ctrl_menu(self, pos): # Get data of selected controller row = self._widget.table_view.rowAt(pos.y()) if row < 0: return # Cursor is not under a valid item ctrl = self._controllers[row] # Show context menu menu = QMenu(self._widget.table_view) if ctrl.state == 'running': action_stop = menu.addAction(self._icons['stopped'], 'Stop') action_kill = menu.addAction(self._icons['uninitialized'], 'Stop and Unload') elif ctrl.state == 'stopped': action_start = menu.addAction(self._icons['running'], 'Start') action_unload = menu.addAction(self._icons['uninitialized'], 'Unload') elif ctrl.state == 'uninitialized': action_load = menu.addAction(self._icons['stopped'], 'Load') action_spawn = menu.addAction(self._icons['running'], 'Load and Start') action = menu.exec_(self._widget.table_view.mapToGlobal(pos)) # Evaluate user action if ctrl.state == 'running': if action is action_stop: self._stop_controller(ctrl.name) elif action is action_kill: self._stop_controller(ctrl.name) self._unload_controller(ctrl.name) elif ctrl.state == 'stopped': if action is action_start: self._start_controller(ctrl.name) elif action is action_unload: self._unload_controller(ctrl.name) elif ctrl.state == 'uninitialized': if action is action_load: self._load_controller(ctrl.name) if action is action_spawn: self._load_controller(ctrl.name) self._start_controller(ctrl.name)
def __init__(self, timeline, event): super(TimelinePopupMenu, self).__init__() self.parent = timeline self.timeline = timeline self._reset_timeline = self.addAction('Reset Timeline') self._play_all = self.addAction('Play All Messages') self._play_all.setCheckable(True) self._play_all.setChecked(self.timeline.play_all) self.addSeparator() submenu = self.addMenu('Thumbnails...') self._thumbnail_show_action = submenu.addAction('Show All') self._thumbnail_hide_action = submenu.addAction('Hide All') submenu.addSeparator() self._renderers = self.timeline._timeline_frame.get_renderers() self._thumbnail_actions = [] for topic, renderer in self._renderers: self._thumbnail_actions.append(submenu.addAction(topic)) self._thumbnail_actions[-1].setCheckable(True) self._thumbnail_actions[-1].setChecked( self.timeline._timeline_frame.is_renderer_active(topic)) self._topics = self.timeline._timeline_frame.topics view_topics_menu = self.addMenu('View (by Topic)') self._topic_actions = [] for topic in self._topics: datatype = self.timeline.get_datatype(topic) # View... / topic topic_menu = QMenu(topic, self) viewer_types = self.timeline._timeline_frame.get_viewer_types( datatype) # View... / topic / Viewer for viewer_type in viewer_types: tempaction = topic_menu.addAction(viewer_type.name) tempaction.setData(viewer_type) self._topic_actions.append(tempaction) view_topics_menu.addMenu(topic_menu) view_type_menu = self.addMenu('View (by Type)') self._topics_by_type = self.timeline._timeline_frame._topics_by_datatype self._type_actions = [] for datatype in self._topics_by_type: # View... / datatype datatype_menu = QMenu(datatype, self) datatype_topics = self._topics_by_type[datatype] viewer_types = self.timeline._timeline_frame.get_viewer_types( datatype) for topic in [t for t in self._topics if t in datatype_topics]: # use timeline ordering topic_menu = QMenu(topic, datatype_menu) # View... / datatype / topic / Viewer for viewer_type in viewer_types: tempaction = topic_menu.addAction(viewer_type.name) tempaction.setData(viewer_type) self._topic_actions.append(tempaction) datatype_menu.addMenu(topic_menu) view_type_menu.addMenu(datatype_menu) self.addSeparator() submenu = self.addMenu('Publish...') self._publish_all = submenu.addAction('Publish All') self._publish_none = submenu.addAction('Publish None') submenu.addSeparator() self._publish_actions = [] for topic in self._topics: self._publish_actions.append(submenu.addAction(topic)) self._publish_actions[-1].setCheckable(True) self._publish_actions[-1].setChecked( self.timeline.is_publishing(topic)) action = self.exec_(event.globalPos()) if action is not None and action != 0: self.process(action)
class EditorWidget(QWidget): ''' This class is abstract -- its child classes should be instantiated. There exist two kinds of "update" methods: - _update_paramserver for Parameter Server. - update_value for the value displayed on GUI. ''' def __init__(self, updater, config): ''' @param updater: A class that extends threading.Thread. @type updater: rqt_reconfigure.param_updater.ParamUpdater ''' super(EditorWidget, self).__init__() self._updater = updater self.param_name = config['name'] self.param_default = config['default'] self.param_description = config['description'] self.old_value = None self.cmenu = QMenu() self.cmenu.addAction(self.tr('Set to Default')).triggered.connect(self._set_to_default) def _update_paramserver(self, value): ''' Update the value on Parameter Server. ''' if value != self.old_value: self.update_configuration(value) self.old_value = value def update_value(self, value): ''' To be implemented in subclass, but still used. Update the value that's displayed on the arbitrary GUI component based on user's input. This method is not called from the GUI thread, so any changes to QObjects will need to be done through a signal. ''' self.old_value = value def update_configuration(self, value): self._updater.update({self.param_name: value}) def display(self, grid): ''' Should be overridden in subclass. :type grid: QFormLayout ''' self._paramname_label.setText(self.param_name) # label_paramname = QLabel(self.param_name) # label_paramname.setWordWrap(True) self._paramname_label.setMinimumWidth(100) grid.addRow(self._paramname_label, self) self.setToolTip(self.param_description) self._paramname_label.setToolTip(self.param_description) self._paramname_label.contextMenuEvent = self.contextMenuEvent def close(self): ''' Should be overridden in subclass. ''' pass def _set_to_default(self): self._update_paramserver(self.param_default) def contextMenuEvent(self, e): self.cmenu.exec_(e.globalPos())
def _create_tag_menu(self, parent=None): # creates a tag menu tag_menu = QMenu("ROS Tags", parent) # group tag add_group_tag_action = QAction("<group>", self, statusTip="", triggered=self._on_add_group_tag) add_group_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+g")) tag_menu.addAction(add_group_tag_action) # node tag add_node_tag_action = QAction("<node>", self, statusTip="", triggered=self._on_add_node_tag) add_node_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+n")) tag_menu.addAction(add_node_tag_action) # node tag with all attributes add_node_tag_all_action = QAction("<node all>", self, statusTip="", triggered=self._on_add_node_tag_all) tag_menu.addAction(add_node_tag_all_action) # include tag with all attributes add_include_tag_all_action = QAction("<include>", self, statusTip="", triggered=self._on_add_include_tag_all) add_include_tag_all_action.setShortcuts(QKeySequence("Ctrl+Shift+i")) tag_menu.addAction(add_include_tag_all_action) # remap add_remap_tag_action = QAction("<remap>", self, statusTip="", triggered=self._on_add_remap_tag) add_remap_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+r")) tag_menu.addAction(add_remap_tag_action) # env tag add_env_tag_action = QAction("<env>", self, statusTip="", triggered=self._on_add_env_tag) tag_menu.addAction(add_env_tag_action) # param tag add_param_clipboard_tag_action = QAction("<param value>", self, statusTip="add value from clipboard", triggered=self._on_add_param_clipboard_tag) add_param_clipboard_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+p")) tag_menu.addAction(add_param_clipboard_tag_action) add_param_tag_action = QAction("<param>", self, statusTip="", triggered=self._on_add_param_tag) add_param_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+Alt+p")) tag_menu.addAction(add_param_tag_action) # param tag with all attributes add_param_tag_all_action = QAction("<param all>", self, statusTip="", triggered=self._on_add_param_tag_all) tag_menu.addAction(add_param_tag_all_action) # rosparam tag with all attributes add_rosparam_tag_all_action = QAction("<rosparam>", self, statusTip="", triggered=self._on_add_rosparam_tag_all) tag_menu.addAction(add_rosparam_tag_all_action) # arg tag with default definition add_arg_tag_default_action = QAction("<arg default>", self, statusTip="", triggered=self._on_add_arg_tag_default) add_arg_tag_default_action.setShortcuts(QKeySequence("Ctrl+Shift+a")) tag_menu.addAction(add_arg_tag_default_action) # arg tag with value definition add_arg_tag_value_action = QAction("<arg value>", self, statusTip="", triggered=self._on_add_arg_tag_value) add_arg_tag_value_action.setShortcuts(QKeySequence("Ctrl+Alt+a")) tag_menu.addAction(add_arg_tag_value_action) # test tag add_test_tag_action = QAction("<test>", self, statusTip="", triggered=self._on_add_test_tag) add_test_tag_action.setShortcuts(QKeySequence("Ctrl+Alt+t")) tag_menu.addAction(add_test_tag_action) # test tag with all attributes add_test_tag_all_action = QAction("<test all>", self, statusTip="", triggered=self._on_add_test_tag_all) tag_menu.addAction(add_test_tag_all_action) sub_cp_menu = QMenu("Custom parameters", parent) show_cp_dialog_action = QAction("Show Dialog", self, statusTip="", triggered=self._show_custom_parameter_dialog) show_cp_dialog_action.setShortcuts(QKeySequence("Ctrl+Shift+d")) sub_cp_menu.addAction(show_cp_dialog_action) add_cp_associations_action = QAction("nm/associations", self, statusTip="", triggered=self._on_add_cp_associations) add_cp_associations_action.setShortcuts(QKeySequence("Ctrl+Alt+a")) sub_cp_menu.addAction(add_cp_associations_action) sub_cp_as_menu = QMenu("Autostart", parent) add_cp_as_delay_action = QAction("delay", self, statusTip="", triggered=self._on_add_cp_as_delay) sub_cp_as_menu.addAction(add_cp_as_delay_action) add_cp_as_exclude_action = QAction("exclude", self, statusTip="", triggered=self._on_add_cp_as_exclude) sub_cp_as_menu.addAction(add_cp_as_exclude_action) add_cp_as_req_publisher_action = QAction("required publisher", self, statusTip="", triggered=self._on_add_cp_as_req_publisher) sub_cp_as_menu.addAction(add_cp_as_req_publisher_action) sub_cp_menu.addMenu(sub_cp_as_menu) sub_cp_r_menu = QMenu("Respawn", parent) add_cp_r_max_action = QAction("max", self, statusTip="", triggered=self._on_add_cp_r_max) sub_cp_r_menu.addAction(add_cp_r_max_action) add_cp_r_min_runtime_action = QAction("min_runtime", self, statusTip="", triggered=self._on_add_cp_r_min_runtime) sub_cp_r_menu.addAction(add_cp_r_min_runtime_action) add_cp_r_delay_action = QAction("delay", self, statusTip="", triggered=self._on_add_cp_r_delay) sub_cp_r_menu.addAction(add_cp_r_delay_action) sub_cp_menu.addMenu(sub_cp_r_menu) add_cp_capability_group_action = QAction("capability_group", self, statusTip="", triggered=self._on_add_cp_capability_group) add_cp_capability_group_action.setShortcuts(QKeySequence("Ctrl+Alt+p")) sub_cp_menu.addAction(add_cp_capability_group_action) add_cp_kill_on_stop_action = QAction("nm/kill_on_stop", self, statusTip="True or time to wait in ms", triggered=self._on_add_cp_kill_on_stop) add_cp_kill_on_stop_action.setShortcuts(QKeySequence("Ctrl+Shift+k")) sub_cp_menu.addAction(add_cp_kill_on_stop_action) tag_menu.addMenu(sub_cp_menu) return tag_menu
def _rightclick_menu(self, event): """ Dynamically builds the rightclick menu based on the unique column data from the passed in datamodel and then launches it modally :param event: the mouse event object, ''QMouseEvent'' """ severities = {} for severity, label in Message.SEVERITY_LABELS.items(): if severity in self._model.get_unique_severities(): severities[severity] = label nodes = sorted(self._model.get_unique_nodes()) topics = sorted(self._model.get_unique_topics()) # menutext entries turned into menutext = [] menutext.append([ self.tr('Exclude'), [[self.tr('Severity'), severities], [self.tr('Node'), nodes], [self.tr('Topic'), topics], [self.tr('Selected Message(s)')]] ]) menutext.append([ self.tr('Highlight'), [[self.tr('Severity'), severities], [self.tr('Node'), nodes], [self.tr('Topic'), topics], [self.tr('Selected Message(s)')]] ]) menutext.append([self.tr('Copy Selected')]) menutext.append([self.tr('Browse Selected')]) menu = QMenu() submenus = [] subsubmenus = [] for item in menutext: if len(item) > 1: submenus.append(QMenu(item[0], menu)) for subitem in item[1]: if len(subitem) > 1: subsubmenus.append(QMenu(subitem[0], submenus[-1])) if isinstance(subitem[1], dict): for key in sorted(subitem[1].keys()): action = subsubmenus[-1].addAction( subitem[1][key]) action.setData(key) else: for subsubitem in subitem[1]: subsubmenus[-1].addAction(subsubitem) submenus[-1].addMenu(subsubmenus[-1]) else: submenus[-1].addAction(subitem[0]) menu.addMenu(submenus[-1]) else: menu.addAction(item[0]) action = menu.exec_(event.globalPos()) if action is None or action == 0: return elif action.text() == self.tr('Browse Selected'): self._show_browsers() elif action.text() == self.tr('Copy Selected'): rowlist = [] for current in self.table_view.selectionModel().selectedIndexes(): rowlist.append(self._proxy_model.mapToSource(current).row()) copytext = self._model.get_selected_text(rowlist) if copytext is not None: clipboard = QApplication.clipboard() clipboard.setText(copytext) elif action.text() == self.tr('Selected Message(s)'): if action.parentWidget().title() == self.tr('Highlight'): self._process_highlight_exclude_filter(action.text(), 'Message', False) elif action.parentWidget().title() == self.tr('Exclude'): self._process_highlight_exclude_filter(action.text(), 'Message', True) else: raise RuntimeError( "Menu format corruption in ConsoleWidget._rightclick_menu()" ) else: # This processes the dynamic list entries (severity, node and topic) try: roottitle = action.parentWidget().parentWidget().title() except: raise RuntimeError( "Menu format corruption in ConsoleWidget._rightclick_menu()" ) if roottitle == self.tr('Highlight'): self._process_highlight_exclude_filter( action.text(), action.parentWidget().title(), False) elif roottitle == self.tr('Exclude'): self._process_highlight_exclude_filter( action.text(), action.parentWidget().title(), True) else: raise RuntimeError( "Unknown Root Action %s selected in ConsoleWidget._rightclick_menu()" % roottitle)
def _rightclick_menu(self, event): """ Dynamically builds the rightclick menu based on the unique column data from the passed in datamodel and then launches it modally :param event: the mouse event object, ''QMouseEvent'' """ severities = {} for severity, label in Message.SEVERITY_LABELS.items(): if severity in self._model.get_unique_severities(): severities[severity] = label nodes = sorted(self._model.get_unique_nodes()) topics = sorted(self._model.get_unique_topics()) # menutext entries turned into menutext = [] menutext.append([self.tr('Exclude'), [[self.tr('Severity'), severities], [self.tr('Node'), nodes], [self.tr('Topic'), topics], [self.tr('Selected Message(s)')]]]) menutext.append([self.tr('Highlight'), [[self.tr('Severity'), severities], [self.tr('Node'), nodes], [self.tr('Topic'), topics], [self.tr('Selected Message(s)')]]]) menutext.append([self.tr('Copy Selected')]) menutext.append([self.tr('Browse Selected')]) menu = QMenu() submenus = [] subsubmenus = [] for item in menutext: if len(item) > 1: submenus.append(QMenu(item[0], menu)) for subitem in item[1]: if len(subitem) > 1: subsubmenus.append(QMenu(subitem[0], submenus[-1])) if isinstance(subitem[1], dict): for key in sorted(subitem[1].keys()): action = subsubmenus[-1].addAction(subitem[1][key]) action.setData(key) else: for subsubitem in subitem[1]: subsubmenus[-1].addAction(subsubitem) submenus[-1].addMenu(subsubmenus[-1]) else: submenus[-1].addAction(subitem[0]) menu.addMenu(submenus[-1]) else: menu.addAction(item[0]) action = menu.exec_(event.globalPos()) if action is None or action == 0: return elif action.text() == self.tr('Browse Selected'): self._show_browsers() elif action.text() == self.tr('Copy Selected'): rowlist = [] for current in self.table_view.selectionModel().selectedIndexes(): rowlist.append(self._proxy_model.mapToSource(current).row()) copytext = self._model.get_selected_text(rowlist) if copytext is not None: clipboard = QApplication.clipboard() clipboard.setText(copytext) elif action.text() == self.tr('Selected Message(s)'): if action.parentWidget().title() == self.tr('Highlight'): self._process_highlight_exclude_filter(action.text(), 'Message', False) elif action.parentWidget().title() == self.tr('Exclude'): self._process_highlight_exclude_filter(action.text(), 'Message', True) else: raise RuntimeError("Menu format corruption in ConsoleWidget._rightclick_menu()") else: # This processes the dynamic list entries (severity, node and topic) try: roottitle = action.parentWidget().parentWidget().title() except: raise RuntimeError("Menu format corruption in ConsoleWidget._rightclick_menu()") if roottitle == self.tr('Highlight'): self._process_highlight_exclude_filter(action.text(), action.parentWidget().title(), False) elif roottitle == self.tr('Exclude'): self._process_highlight_exclude_filter(action.text(), action.parentWidget().title(), True) else: raise RuntimeError("Unknown Root Action %s selected in ConsoleWidget._rightclick_menu()" % roottitle)
def _rightclick_menu(self, event): """ Dynamically builds the rightclick menu based on the unique column data from the passed in datamodel and then launches it modally :param event: the mouse event object, ''QMouseEvent'' """ severities = self._datamodel.get_unique_col_data(1) nodes = self._datamodel.get_unique_col_data(2) topics = self._datamodel.get_unique_col_data(4) temp = [] for topic in topics: if topic.find(', ') == -1: temp.append(topic) else: temp = temp + topic.split(', ') topics = list(set(temp)) columns = list(self._datamodel.message_members()) for index in range(len(columns)): columns[index] = [columns[index][1:].capitalize()] # menutext entries turned into menutext = [] menutext.append([self.tr('Exclude'), [[self.tr('Severity'), severities], [self.tr('Node'), nodes], [self.tr('Topic'), topics], [self.tr('Selected Message(s)')]]]) menutext.append([self.tr('Highlight'), [[self.tr('Severity'), severities], [self.tr('Node'), nodes], [self.tr('Topic'), topics], [self.tr('Selected Message(s)')]]]) menutext.append([self.tr('Copy Selected')]) menutext.append([self.tr('Browse Selected')]) menu = QMenu() submenus = [] subsubmenus = [] for item in menutext: if len(item) > 1: submenus.append(QMenu(item[0], menu)) for subitem in item[1]: if len(subitem) > 1: subsubmenus.append(QMenu(subitem[0], submenus[-1])) for subsubitem in subitem[1]: subsubmenus[-1].addAction(subsubitem) submenus[-1].addMenu(subsubmenus[-1]) else: submenus[-1].addAction(subitem[0]) menu.addMenu(submenus[-1]) else: menu.addAction(item[0]) action = menu.exec_(event.globalPos()) if action is None or action == 0: return elif action.text() == self.tr('Browse Selected'): self._show_browsers() elif action.text() == self.tr('Copy Selected'): rowlist = [] for current in self.table_view.selectionModel().selectedIndexes(): rowlist.append(self._proxymodel.mapToSource(current).row()) copytext = self._datamodel.get_selected_text(rowlist) if copytext is not None: clipboard = QApplication.clipboard() clipboard.setText(copytext) elif action.text() == self.tr('Selected Message(s)'): if action.parentWidget().title() == self.tr('Highlight'): self._process_highlight_exclude_filter(action.text(), 'Message', False) elif action.parentWidget().title() == self.tr('Exclude'): self._process_highlight_exclude_filter(action.text(), 'Message', True) else: raise RuntimeError("Menu format corruption in ConsoleWidget._rightclick_menu()") else: # This processes the dynamic list entries (severity, node and topic) try: roottitle = action.parentWidget().parentWidget().title() except: raise RuntimeError("Menu format corruption in ConsoleWidget._rightclick_menu()") if roottitle == self.tr('Highlight'): self._process_highlight_exclude_filter(action.text(), action.parentWidget().title(), False) elif roottitle == self.tr('Exclude'): self._process_highlight_exclude_filter(action.text(), action.parentWidget().title(), True) else: raise RuntimeError("Unknown Root Action %s selected in ConsoleWidget._rightclick_menu()" % roottitle) self.update_status()
def _create_tag_menu(self, parent=None): # creates a tag menu tag_menu = QMenu("ROS Tags", parent) # group tag add_group_tag_action = QAction("<group>", self, statusTip="", triggered=self._on_add_group_tag) add_group_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+g")) tag_menu.addAction(add_group_tag_action) # node tag add_node_tag_action = QAction("<node>", self, statusTip="", triggered=self._on_add_node_tag) add_node_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+n")) tag_menu.addAction(add_node_tag_action) # node tag with all attributes add_node_tag_all_action = QAction("<node all>", self, statusTip="", triggered=self._on_add_node_tag_all) tag_menu.addAction(add_node_tag_all_action) # include tag with all attributes add_include_tag_all_action = QAction("<include>", self, statusTip="", triggered=self._on_add_include_tag_all) add_include_tag_all_action.setShortcuts(QKeySequence("Ctrl+Shift+i")) tag_menu.addAction(add_include_tag_all_action) # remap add_remap_tag_action = QAction("<remap>", self, statusTip="", triggered=self._on_add_remap_tag) add_remap_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+r")) tag_menu.addAction(add_remap_tag_action) # env tag add_env_tag_action = QAction("<env>", self, statusTip="", triggered=self._on_add_env_tag) tag_menu.addAction(add_env_tag_action) # param tag add_param_tag_action = QAction("<param>", self, statusTip="", triggered=self._on_add_param_tag) add_param_tag_action.setShortcuts(QKeySequence("Ctrl+Shift+p")) tag_menu.addAction(add_param_tag_action) # param capability group tag add_param_cap_group_tag_action = QAction("<param capability group>", self, statusTip="", triggered=self._on_add_param_cap_group_tag) add_param_cap_group_tag_action.setShortcuts(QKeySequence("Ctrl+Alt+p")) tag_menu.addAction(add_param_cap_group_tag_action) # param tag with all attributes add_param_tag_all_action = QAction("<param all>", self, statusTip="", triggered=self._on_add_param_tag_all) tag_menu.addAction(add_param_tag_all_action) # rosparam tag with all attributes add_rosparam_tag_all_action = QAction("<rosparam>", self, statusTip="", triggered=self._on_add_rosparam_tag_all) tag_menu.addAction(add_rosparam_tag_all_action) # arg tag with default definition add_arg_tag_default_action = QAction("<arg default>", self, statusTip="", triggered=self._on_add_arg_tag_default) add_arg_tag_default_action.setShortcuts(QKeySequence("Ctrl+Shift+a")) tag_menu.addAction(add_arg_tag_default_action) # arg tag with value definition add_arg_tag_value_action = QAction("<arg value>", self, statusTip="", triggered=self._on_add_arg_tag_value) add_arg_tag_value_action.setShortcuts(QKeySequence("Ctrl+Alt+a")) tag_menu.addAction(add_arg_tag_value_action) # test tag add_test_tag_action = QAction("<test>", self, statusTip="", triggered=self._on_add_test_tag) add_test_tag_action.setShortcuts(QKeySequence("Ctrl+Alt+t")) tag_menu.addAction(add_test_tag_action) # test tag with all attributes add_test_tag_all_action = QAction("<test all>", self, statusTip="", triggered=self._on_add_test_tag_all) tag_menu.addAction(add_test_tag_all_action) return tag_menu
class LaunchFilesWidget(QDockWidget): ''' Launch file browser. ''' load_signal = Signal(str, dict, str) ''' load the launch file with given arguments (launchfile, args, masteruri)''' load_profile_signal = Signal(str) ''' load the profile file ''' edit_signal = Signal(str) ''' list of paths to open in an editor ''' transfer_signal = Signal(list) ''' list of tuples of (url, path) selected for transfer ''' save_profile_signal = Signal(str) ''':ivar str save_profile_signa: the signal is emitted, to save profile. (current path selected in launch files)''' def __init__(self, parent=None): ''' Creates the window, connects the signals and init the class. ''' QDockWidget.__init__(self, parent) # initialize parameter self.__current_path = os.path.expanduser('~') # load the UI file ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ui', 'LaunchFilesDockWidget.ui') loadUi(ui_file, self, custom_widgets={'EnhancedLineEdit': EnhancedLineEdit}) self.ui_button_progress_cancel_cfg.setIcon( nm.settings().icon('crystal_clear_button_close.png')) self.ui_button_reload.setIcon( nm.settings().icon('oxygen_view_refresh.png')) self.ui_button_edit.setIcon( nm.settings().icon('crystal_clear_edit_launch.png')) self.ui_button_new.setIcon(nm.settings().icon('crystal_clear_add.png')) self.ui_button_transfer.setIcon( nm.settings().icon('crystal_clear_launch_file_transfer.png')) self.ui_button_save_profile.setIcon( nm.settings().icon('crystal_clear_profile_new.png')) self.ui_button_load.setIcon( nm.settings().icon('crystal_clear_launch_file.png')) self._current_search = '' pal = self.palette() self._default_color = pal.color(QPalette.Window) # initialize the progress queue self.progress_queue = ProgressQueue(self.ui_frame_progress_cfg, self.ui_bar_progress_cfg, self.ui_button_progress_cancel_cfg, 'Launch File') # initialize the view for the launch files self.launchlist_model = LaunchListModel( progress_queue=self.progress_queue, viewobj=self.ui_file_view) self.launchlist_proxy_model = QSortFilterProxyModel(self) self.launchlist_proxy_model.setSourceModel(self.launchlist_model) self.name_delegate = HTMLDelegate(check_for_ros_names=False, palette=self.palette()) self.ui_file_view.setItemDelegateForColumn(0, self.name_delegate) self.ui_file_view.setModel(self.launchlist_proxy_model) self.ui_file_view.setAlternatingRowColors(True) self.ui_file_view.activated.connect(self.on_launch_selection_activated) self.ui_file_view.setDragDropMode(QAbstractItemView.DragOnly) self.ui_file_view.setDragEnabled(True) sm = self.ui_file_view.selectionModel() sm.selectionChanged.connect(self.on_ui_file_view_selection_changed) self.launchlist_model.pathlist_handled.connect( self.on_pathlist_handled) self.launchlist_model.error_on_path.connect(self.on_error_on_path) self.ui_search_line.refresh_signal.connect(self.set_package_filter) self.ui_search_line.stop_signal.connect(self.stop) # connect to the button signals self.ui_button_reload.clicked.connect(self.on_reload_clicked) self.ui_button_edit.clicked.connect(self.on_edit_xml_clicked) #self.ui_button_new.clicked.connect(self.on_new_xml_clicked) self.ui_button_transfer.clicked.connect(self.on_transfer_file_clicked) self.ui_button_save_profile.clicked.connect( self.on_save_profile_clicked) self.ui_button_load.clicked.connect(self.on_load_xml_clicked) # add menu to create fiel or directory self._menu_add = QMenu() create_file_action = QAction( nm.settings().icon('crystal_clear_launch_file_new.png'), "create file", self, statusTip="", triggered=self.on_new_xml_clicked) create_dir_action = QAction( nm.settings().icon('crystal_clear_folder.png'), "create directory", self, statusTip="", triggered=self.on_new_dir_clicked) self._menu_add.addAction(create_file_action) self._menu_add.addAction(create_dir_action) self.ui_button_new.setMenu(self._menu_add) self._masteruri2name = {} self._reload_timer = None def stop(self): ''' Cancel the executing queued actions. This method must be called at the exit! ''' self.progress_queue.stop() self.ui_search_line.set_process_active(False) self._stop_timer_reload() def set_current_master(self, masteruri, mastername): self.launchlist_model.set_current_master(masteruri, mastername) self._masteruri2name[masteruri.rstrip(os.path.sep)] = mastername try: color = QColor.fromRgb(nm.settings().host_color( self._masteruri2name[nmdurl.masteruri( self.launchlist_model.current_path)], self._default_color.rgb())) self._new_color(color) except Exception as _: pass # import traceback # print traceback.format_exc() # rospy.logwarn("Error while set color in launch dock: %s" % utf8(err)) def on_launch_selection_activated(self, activated): ''' Tries to load the launch file, if one was activated. ''' selected = self._pathItemsFromIndexes( self.ui_file_view.selectionModel().selectedIndexes(), False) for item in selected: try: self.ui_search_line.set_process_active(True) lfile = self.launchlist_model.expand_item(item.path, item.id) # self.ui_search_line.setText('') if lfile is not None: self.ui_search_line.set_process_active(False) if item.is_launch_file(): nm.settings().launch_history_add(item.path) self.load_signal.emit(item.path, {}, None) elif item.is_profile_file(): nm.settings().launch_history_add(item.path) self.load_profile_signal.emit(item.path) elif item.is_config_file(): self.edit_signal.emit(lfile) if self.launchlist_model.current_path: self.setWindowTitle( 'Launch @%s' % get_hostname(self.launchlist_model.current_grpc)) else: self.setWindowTitle('Launch files') except Exception as e: import traceback print(traceback.format_exc()) rospy.logwarn("Error while load launch file %s: %s" % (item, utf8(e))) MessageBox.warning( self, "Load error", 'Error while load launch file:\n%s' % item.name, "%s" % utf8(e)) try: color = QColor.fromRgb(nm.settings().host_color( self._masteruri2name[nmdurl.masteruri( self.launchlist_model.current_path)], self._default_color.rgb())) self._new_color(color) except Exception as _: pass # import traceback # print traceback.format_exc() # rospy.logwarn("Error while set color in launch dock: %s" % utf8(err)) def _new_color(self, color): bg_style_launch_dock = "QWidget#ui_dock_widget_contents { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 %s, stop: 0.7 %s);}" % ( color.name(), self._default_color.name()) self.setStyleSheet("%s" % (bg_style_launch_dock)) def on_pathlist_handled(self, gpath): self.ui_search_line.set_process_active(False) self.ui_button_new.setEnabled(not self.launchlist_model.is_in_root) self._stop_timer_reload() def on_error_on_path(self, gpath): if gpath == self._current_search or gpath == self.launchlist_model.current_path: self.ui_search_line.set_process_active(False) if self.launchlist_model.is_in_root: self._reload_timer = threading.Timer( 2., nm.nmd().file.list_path_threaded) self._reload_timer.start() def _stop_timer_reload(self): if self._reload_timer is not None and self._reload_timer.is_alive(): try: self._reload_timer.cancel() self._reload_timer = None except Exception: pass def _on_timer_reload_callback(self, event=None): nm.nmd().file.list_path_threaded(self.launchlist_model.current_path) self._reload_timer = threading.Timer(2., nm.nmd().file.list_path_threaded) self._reload_timer.start() def on_launch_selection_changed(self, selected, deselected): print("selection launch changed") def load_file(self, path, args={}, masteruri=None): ''' Tries to load the launch file, if one was activated. ''' if path is not None: if path.endswith('.launch'): self.load_signal.emit(path, args, masteruri) elif path.endswith('.nmprofile'): self.load_profile_signal.emit(path) def on_ui_file_view_selection_changed(self, selected, deselected): ''' On selection of a launch file, the buttons are enabled otherwise disabled. ''' selected = self._pathItemsFromIndexes( self.ui_file_view.selectionModel().selectedIndexes(), False) for item in selected: islaunch = item.is_launch_file() isconfig = item.is_config_file() isprofile = item.is_profile_file() self.ui_button_edit.setEnabled(islaunch or isconfig or isprofile) self.ui_button_load.setEnabled(islaunch or isprofile) self.ui_button_transfer.setEnabled(islaunch or isconfig) def set_package_filter(self, text): if text: if text.startswith(os.path.sep): self._current_search = nmdurl.join( self.launchlist_model.current_grpc, text) self.launchlist_model.set_path(text) else: # search for a package self.launchlist_model.show_packages(text) self.ui_search_line.set_process_active(False) else: self.launchlist_model.reload_current_path() def on_reload_clicked(self): ''' Clear daemon's cache. ''' self.launchlist_model.reload_current_path(clear_cache=True) def on_edit_xml_clicked(self): ''' Opens an XML editor to edit the launch file. ''' selected = self._pathItemsFromIndexes( self.ui_file_view.selectionModel().selectedIndexes(), False) for item in selected: path = self.launchlist_model.expand_item(item.path, item.id) if path is not None: self.edit_signal.emit(path) def on_new_xml_clicked(self): ''' Creates a new launch file. ''' # get new file from open dialog, use last path if one exists if not self.launchlist_model.is_in_root: items = self.launchlist_model.add_new_item("new.launch", PathItem.LAUNCH_FILE) if items: index = self.launchlist_proxy_model.mapFromSource( self.launchlist_model.index(1, 0)) self.ui_file_view.selectionModel().select( index, QItemSelectionModel.Select) self.ui_file_view.setCurrentIndex(index) self.ui_file_view.edit(index) def on_new_dir_clicked(self): ''' Creates a new directory. ''' # get new file from open dialog, use last path if one exists if not self.launchlist_model.is_in_root: items = self.launchlist_model.add_new_item("new", PathItem.FOLDER) if items: index = self.launchlist_proxy_model.mapFromSource( self.launchlist_model.index(1, 0)) self.ui_file_view.selectionModel().select( index, QItemSelectionModel.Select) self.ui_file_view.setCurrentIndex(index) self.ui_file_view.edit(index) def on_transfer_file_clicked(self): ''' Emit the signal to copy the selected file to a remote host. ''' selected = self._pathItemsFromIndexes( self.ui_file_view.selectionModel().selectedIndexes(), False) paths = list() for item in selected: path = self.launchlist_model.expand_item(item.path, item.id) if path is not None: paths.append(path) if paths: self.transfer_signal.emit(paths) def on_save_profile_clicked(self): # save the profile _netloc, path = nmdurl.split(self.launchlist_model.current_path, with_scheme=True) self.save_profile_signal.emit(path) def on_load_xml_clicked(self): ''' Tries to load the selected launch file. The button is only enabled and this method is called, if the button was enabled by on_launch_selection_clicked() ''' selected = self._pathItemsFromIndexes( self.ui_file_view.selectionModel().selectedIndexes(), False) for item in selected: path = self.launchlist_model.expand_item(item.path, item.id) if path is not None: nm.settings().launch_history_add(item.path) self.load_signal.emit(path, {}, None) def _pathItemsFromIndexes(self, indexes, recursive=True): result = [] for index in indexes: if index.column() == 0: model_index = self.launchlist_proxy_model.mapToSource(index) item = self.launchlist_model.itemFromIndex(model_index) if item is not None and isinstance(item, PathItem): result.append(item) return result def keyPressEvent(self, event): ''' Defines some of shortcuts for navigation/management in launch list view or topics view. ''' key_mod = QApplication.keyboardModifiers() if not self.ui_file_view.state() == QAbstractItemView.EditingState: # remove history file from list by pressing DEL if event == QKeySequence.Delete or (event.key() == Qt.Key_Delete and key_mod & Qt.ShiftModifier): selected = self._pathItemsFromIndexes( self.ui_file_view.selectionModel().selectedIndexes(), False) for item in selected: if item in nm.settings().launch_history: nm.settings().launch_history_remove(item.path) self.launchlist_model.reload_current_path() elif not self.launchlist_model.is_in_root: if key_mod & Qt.ShiftModifier: rem_uri, rem_path = nmdurl.split(item.path) host = rem_uri.split(':') result = MessageBox.question( self, "Delete Question", "Delete %s\n@ %s" % (rem_path, host[0]), buttons=MessageBox.No | MessageBox.Yes) if result == MessageBox.Yes: try: nm.nmd().file.delete(item.path) self.launchlist_model.reload_current_path( clear_cache=True) except Exception as e: rospy.logwarn("Error while delete %s: %s" % (item.path, utf8(e))) MessageBox.warning( self, "Delete error", 'Error while delete:\n%s' % item.name, "%s" % utf8(e)) else: MessageBox.information( self, "Delete Info", "Use Shift+Del to delete files or directories", buttons=MessageBox.Ok) elif not key_mod and event.key( ) == Qt.Key_F4 and self.ui_button_edit.isEnabled(): # open selected launch file in xml editor by F4 self.on_edit_xml_clicked() elif event == QKeySequence.Find: # set focus to filter box for packages self.ui_search_line.setFocus(Qt.ActiveWindowFocusReason) elif event == QKeySequence.Paste: # paste files from clipboard self.launchlist_model.paste_from_clipboard() elif event == QKeySequence.Copy: # copy the selected items as file paths into clipboard selected = self.ui_file_view.selectionModel().selectedIndexes() indexes = [] for s in selected: indexes.append(self.launchlist_proxy_model.mapToSource(s)) self.launchlist_model.copy_to_clipboard(indexes) if self.ui_search_line.hasFocus() and event.key() == Qt.Key_Escape: # cancel package filtering on pressing ESC self.launchlist_model.reload_current_path() self.ui_search_line.setText('') self.ui_file_view.setFocus(Qt.ActiveWindowFocusReason) QDockWidget.keyReleaseEvent(self, event)
class Plot3DWidget(QWidget): _redraw_interval = 40 def __init__(self, initial_topics=None, start_paused=False, buffer_length=100, use_poly=True, no_legend=False): super(Plot3DWidget, self).__init__() self.setObjectName('Plot3DWidget') self._buffer_length = buffer_length self._initial_topics = initial_topics rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('jsk_rqt_plugins'), 'resource', 'plot3d.ui') loadUi(ui_file, self) self.subscribe_topic_button.setIcon(QIcon.fromTheme('add')) self.remove_topic_button.setIcon(QIcon.fromTheme('remove')) self.pause_button.setIcon(QIcon.fromTheme('media-playback-pause')) self.clear_button.setIcon(QIcon.fromTheme('edit-clear')) self.data_plot = MatDataPlot3D(self, self._buffer_length, use_poly, no_legend) self.data_plot_layout.addWidget(self.data_plot) self.data_plot.autoscroll(self.autoscroll_checkbox.isChecked()) self.data_plot.dropEvent = self.dropEvent self.data_plot.dragEnterEvent = self.dragEnterEvent self.subscribe_topic_button.setEnabled(False) if start_paused: self.pause_button.setChecked(True) self._topic_completer = TopicCompleter(self.topic_edit) self._topic_completer.update_topics() self.topic_edit.setCompleter(self._topic_completer) self._start_time = rospy.get_time() self._rosdata = {} self._remove_topic_menu = QMenu() # init and start update timer for plot self._update_plot_timer = QTimer(self) self._update_plot_timer.timeout.connect(self.update_plot) if self._initial_topics: for topic_name in self._initial_topics: self.add_topic(topic_name) self._initial_topics = None @Slot('QDragEnterEvent*') def dragEnterEvent(self, event): # get topic name if not event.mimeData().hasText(): if not hasattr(event.source(), 'selectedItems') or len(event.source().selectedItems()) == 0: qWarning('Plot.dragEnterEvent(): not hasattr(event.source(), selectedItems) or len(event.source().selectedItems()) == 0') return item = event.source().selectedItems()[0] topic_name = item.data(0, Qt.UserRole) if topic_name == None: qWarning('Plot.dragEnterEvent(): not hasattr(item, ros_topic_name_)') return else: topic_name = str(event.mimeData().text()) # check for numeric field type is_numeric, is_array, message = is_slot_numeric(topic_name) if is_numeric and not is_array: event.acceptProposedAction() else: qWarning('Plot.dragEnterEvent(): rejecting: "%s"' % (message)) @Slot('QDropEvent*') def dropEvent(self, event): if event.mimeData().hasText(): topic_name = str(event.mimeData().text()) else: droped_item = event.source().selectedItems()[0] topic_name = str(droped_item.data(0, Qt.UserRole)) self.add_topic(topic_name) @Slot(str) def on_topic_edit_textChanged(self, topic_name): # on empty topic name, update topics if topic_name in ('', '/'): self._topic_completer.update_topics() is_numeric, is_array, message = is_slot_numeric(topic_name) self.subscribe_topic_button.setEnabled(is_numeric and not is_array) self.subscribe_topic_button.setToolTip(message) @Slot() def on_topic_edit_returnPressed(self): if self.subscribe_topic_button.isEnabled(): self.add_topic(str(self.topic_edit.text())) @Slot() def on_subscribe_topic_button_clicked(self): self.add_topic(str(self.topic_edit.text())) @Slot(bool) def on_pause_button_clicked(self, checked): self.enable_timer(not checked) @Slot(bool) def on_autoscroll_checkbox_clicked(self, checked): self.data_plot.autoscroll(checked) @Slot() def on_clear_button_clicked(self): self.clean_up_subscribers() def update_plot(self): if self.data_plot is not None: needs_redraw = False for topic_name, rosdata in self._rosdata.items(): try: data_x, data_y = rosdata.next() if data_x or data_y: self.data_plot.update_values(topic_name, data_x, data_y) needs_redraw = True except RosPlotException as e: qWarning('PlotWidget.update_plot(): error in rosplot: %s' % e) if needs_redraw: self.data_plot.redraw() def _subscribed_topics_changed(self): self._update_remove_topic_menu() if not self.pause_button.isChecked(): # if pause button is not pressed, enable timer based on subscribed topics self.enable_timer(self._rosdata) def _update_remove_topic_menu(self): def make_remove_topic_function(x): return lambda: self.remove_topic(x) self._remove_topic_menu.clear() for topic_name in sorted(self._rosdata.keys()): action = QAction(topic_name, self._remove_topic_menu) action.triggered.connect(make_remove_topic_function(topic_name)) self._remove_topic_menu.addAction(action) self.remove_topic_button.setMenu(self._remove_topic_menu) def add_topic(self, topic_name): if topic_name in self._rosdata: qWarning('PlotWidget.add_topic(): topic already subscribed: %s' % topic_name) return self._rosdata[topic_name] = ROSData(topic_name, self._start_time) if self._rosdata[topic_name].error is not None: qWarning(str(self._rosdata[topic_name].error)) del self._rosdata[topic_name] else: data_x, data_y = self._rosdata[topic_name].next() self.data_plot.add_curve(topic_name, topic_name, data_x, data_y) self._subscribed_topics_changed() def remove_topic(self, topic_name): self._rosdata[topic_name].close() del self._rosdata[topic_name] self.data_plot.remove_curve(topic_name) self._subscribed_topics_changed() def clean_up_subscribers(self): for topic_name, rosdata in self._rosdata.items(): rosdata.close() self.data_plot.remove_curve(topic_name) self._rosdata = {} self._subscribed_topics_changed() def enable_timer(self, enabled=True): if enabled: self._update_plot_timer.start(self._redraw_interval) else: self._update_plot_timer.stop()
class PlotWidget(QWidget): _redraw_interval = 40 def __init__(self, arguments=None, initial_topics=None): super(PlotWidget, self).__init__() self.setObjectName('PlotWidget') ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'plot.ui') loadUi(ui_file, self) self.subscribe_topic_button.setIcon(QIcon.fromTheme('add')) self.remove_topic_button.setIcon(QIcon.fromTheme('remove')) self.pause_button.setIcon(QIcon.fromTheme('media-playback-pause')) self.clear_button.setIcon(QIcon.fromTheme('edit-clear')) self.data_plot = None self.subscribe_topic_button.setEnabled(False) self._topic_completer = TopicCompleter(self.topic_edit) self._topic_completer.update_topics() self.topic_edit.setCompleter(self._topic_completer) self._start_time = rospy.get_time() self._rosdata = {} self._ordered_topics = [] self._remove_topic_menu = QMenu() # init and start update timer for plot self._update_plot_timer = QTimer(self) self._update_plot_timer.timeout.connect(self.update_plot) # save command line arguments self._arguments = arguments self._initial_topics = initial_topics def switch_data_plot_widget(self, data_plot): self.enable_timer(enabled=False) self.data_plot_layout.removeWidget(self.data_plot) if self.data_plot is not None: self.data_plot.close() self.data_plot = data_plot self.data_plot_layout.addWidget(self.data_plot) # setup drag 'n drop self.data_plot.dropEvent = self.dropEvent self.data_plot.dragEnterEvent = self.dragEnterEvent if self._initial_topics: for topic_name in self._initial_topics: self.add_topic(topic_name) self._initial_topics = None else: for topic_name, rosdata in self._rosdata.items(): data_x, data_y = rosdata.next() self.data_plot.add_curve(topic_name, topic_name, data_x, data_y) self._subscribed_topics_changed() @Slot('QDragEnterEvent*') def dragEnterEvent(self, event): # get topic name if not event.mimeData().hasText(): if not hasattr(event.source(), 'selectedItems') or len( event.source().selectedItems()) == 0: qWarning( 'Plot.dragEnterEvent(): not hasattr(event.source(), selectedItems) or len(event.source().selectedItems()) == 0' ) return item = event.source().selectedItems()[0] topic_name = item.data(0, Qt.UserRole) if topic_name == None: qWarning( 'Plot.dragEnterEvent(): not hasattr(item, ros_topic_name_)' ) return else: topic_name = str(event.mimeData().text()) # check for numeric field type is_numeric, is_array, message = is_slot_numeric(topic_name) if is_numeric and not is_array: event.acceptProposedAction() else: qWarning('Plot.dragEnterEvent(): rejecting: "%s"' % (message)) @Slot('QDropEvent*') def dropEvent(self, event): if event.mimeData().hasText(): topic_name = str(event.mimeData().text()) else: droped_item = event.source().selectedItems()[0] topic_name = str(droped_item.data(0, Qt.UserRole)) self.add_topic(topic_name) @Slot(str) def on_topic_edit_textChanged(self, topic_name): # on empty topic name, update topics if topic_name in ('', '/'): self._topic_completer.update_topics() is_numeric, is_array, message = is_slot_numeric(topic_name) self.subscribe_topic_button.setEnabled(is_numeric and not is_array) self.subscribe_topic_button.setToolTip(message) @Slot() def on_subscribe_topic_button_clicked(self): self.add_topic(str(self.topic_edit.text())) @Slot() def on_mass_button_clicked(self): topics = str(self.mass_edit.toPlainText()).split() for topic in topics: self.add_topic(topic) @Slot(bool) def on_pause_button_clicked(self, checked): self.enable_timer(not checked) @Slot() def on_clear_button_clicked(self): self.clean_up_subscribers() def update_plot(self): if self.data_plot is not None: for topic_name, rosdata in self._rosdata.items(): try: data_x, data_y = rosdata.next() self.data_plot.update_values(topic_name, data_x, data_y) except RosPlotException as e: qWarning('PlotWidget.update_plot(): error in rosplot: %s' % e) self.data_plot.redraw() def _subscribed_topics_changed(self): self._update_remove_topic_menu() if self._arguments: if self._arguments.start_paused: self.pause_button.setChecked(True) if not self.pause_button.isChecked(): # if pause button is not pressed, enable timer based on subscribed topics self.enable_timer(self._rosdata) def _update_remove_topic_menu(self): def make_remove_topic_function(x): return lambda: self.remove_topic(x) self._remove_topic_menu.clear() for topic_name in sorted(self._rosdata.keys()): action = QAction(topic_name, self._remove_topic_menu) action.triggered.connect(make_remove_topic_function(topic_name)) self._remove_topic_menu.addAction(action) self.remove_topic_button.setMenu(self._remove_topic_menu) def add_topic(self, topic_name): if topic_name in self._rosdata: qWarning('PlotWidget.add_topic(): topic already subscribed: %s' % topic_name) return self._ordered_topics.append(topic_name) self._rosdata[topic_name] = ROSData(topic_name, self._start_time) data_x, data_y = self._rosdata[topic_name].next() self.data_plot.add_curve(topic_name, topic_name, data_x, data_y) self._subscribed_topics_changed() def remove_topic(self, topic_name): self._rosdata[topic_name].close() del self._rosdata[topic_name] self._ordered_topics.remove(topic_name) self.data_plot.remove_curve(topic_name) self._subscribed_topics_changed() def clean_up_subscribers(self): for topic_name, rosdata in self._rosdata.items(): rosdata.close() self.data_plot.remove_curve(topic_name) self._rosdata = {} self._ordered_topics = [] self._subscribed_topics_changed() def enable_timer(self, enabled=True): if enabled: self._update_plot_timer.start(self._redraw_interval) else: self._update_plot_timer.stop()
def __init__(self, timeline, event, menu_topic): super(TimelinePopupMenu, self).__init__() self.parent = timeline self.timeline = timeline if menu_topic is not None: self.setTitle(menu_topic) self._menu_topic = menu_topic else: self._menu_topic = None self._reset_timeline = self.addAction('Reset Timeline') self._play_all = self.addAction('Play All Messages') self._play_all.setCheckable(True) self._play_all.setChecked(self.timeline.play_all) self.addSeparator() self._renderers = self.timeline._timeline_frame.get_renderers() self._thumbnail_actions = [] # create thumbnail menu items if menu_topic is None: submenu = self.addMenu('Thumbnails...') self._thumbnail_show_action = submenu.addAction('Show All') self._thumbnail_hide_action = submenu.addAction('Hide All') submenu.addSeparator() for topic, renderer in self._renderers: self._thumbnail_actions.append(submenu.addAction(topic)) self._thumbnail_actions[-1].setCheckable(True) self._thumbnail_actions[-1].setChecked(self.timeline._timeline_frame.is_renderer_active(topic)) else: self._thumbnail_show_action = None self._thumbnail_hide_action = None for topic, renderer in self._renderers: if menu_topic == topic: self._thumbnail_actions.append(self.addAction("Thumbnail")) self._thumbnail_actions[-1].setCheckable(True) self._thumbnail_actions[-1].setChecked(self.timeline._timeline_frame.is_renderer_active(topic)) # create view menu items self._topic_actions = [] self._type_actions = [] if menu_topic is None: self._topics = self.timeline._timeline_frame.topics view_topics_menu = self.addMenu('View (by Topic)') for topic in self._topics: datatype = self.timeline.get_datatype(topic) # View... / topic topic_menu = QMenu(topic, self) viewer_types = self.timeline._timeline_frame.get_viewer_types(datatype) # View... / topic / Viewer for viewer_type in viewer_types: tempaction = topic_menu.addAction(viewer_type.name) tempaction.setData(viewer_type) self._topic_actions.append(tempaction) view_topics_menu.addMenu(topic_menu) view_type_menu = self.addMenu('View (by Type)') self._topics_by_type = self.timeline._timeline_frame._topics_by_datatype for datatype in self._topics_by_type: # View... / datatype datatype_menu = QMenu(datatype, self) datatype_topics = self._topics_by_type[datatype] viewer_types = self.timeline._timeline_frame.get_viewer_types(datatype) for topic in [t for t in self._topics if t in datatype_topics]: # use timeline ordering topic_menu = QMenu(topic, datatype_menu) # View... / datatype / topic / Viewer for viewer_type in viewer_types: tempaction = topic_menu.addAction(viewer_type.name) tempaction.setData(viewer_type) self._topic_actions.append(tempaction) datatype_menu.addMenu(topic_menu) view_type_menu.addMenu(datatype_menu) else: view_menu = self.addMenu("View") datatype = self.timeline.get_datatype(menu_topic) viewer_types = self.timeline._timeline_frame.get_viewer_types(datatype) for viewer_type in viewer_types: tempaction = view_menu.addAction(viewer_type.name) tempaction.setData(viewer_type) self._topic_actions.append(tempaction) self.addSeparator() # create publish menu items self._publish_actions = [] if menu_topic is None: submenu = self.addMenu('Publish...') self._publish_all = submenu.addAction('Publish All') self._publish_none = submenu.addAction('Publish None') submenu.addSeparator() for topic in self._topics: self._publish_actions.append(submenu.addAction(topic)) self._publish_actions[-1].setCheckable(True) self._publish_actions[-1].setChecked(self.timeline.is_publishing(topic)) else: self._publish_actions.append(self.addAction("Publish")) self._publish_actions[-1].setCheckable(True) self._publish_actions[-1].setChecked(self.timeline.is_publishing(menu_topic)) self._publish_all = None self._publish_none = None action = self.exec_(event.globalPos()) if action is not None and action != 0: self.process(action)