class AppendDialog(QDialog): def __init__(self, parent, compatibles, title="Append data"): super().__init__(parent) self.setWindowTitle(title) vbox = QVBoxLayout(self) grid = QGridLayout() grid.addWidget(QLabel("Source"), 0, 0, Qt.AlignCenter) grid.addWidget(QLabel("Destination"), 0, 2, Qt.AlignCenter) source = QListWidget(self) source.setAcceptDrops(True) source.setDragEnabled(True) source.setSelectionMode(QAbstractItemView.ExtendedSelection) source.setDefaultDropAction(Qt.DropAction.MoveAction) source.insertItems(0, [d["name"] for d in compatibles]) grid.addWidget(source, 1, 0) grid.addWidget(QLabel("->"), 1, 1, Qt.AlignHCenter) self.destination = QListWidget(self) self.destination.setAcceptDrops(True) self.destination.setDragEnabled(True) self.destination.setSelectionMode(QAbstractItemView.ExtendedSelection) self.destination.setDefaultDropAction(Qt.DropAction.MoveAction) grid.addWidget(self.destination, 1, 2) vbox.addLayout(grid) self.buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.buttonbox.accepted.connect(self.accept) self.buttonbox.rejected.connect(self.reject) vbox.addWidget(self.buttonbox) vbox.setSizeConstraint(QVBoxLayout.SetFixedSize) self.destination.model().rowsInserted.connect(self.toggle_buttons) self.destination.model().rowsRemoved.connect(self.toggle_buttons) self.toggle_buttons() @property def names(self): names = [] for it in range(self.destination.count()): names.append(self.destination.item(it).text()) return names @Slot() def toggle_buttons(self): """Toggle OK button. """ if self.destination.count() > 0: self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(True) else: self.buttonbox.button(QDialogButtonBox.Ok).setEnabled(False)
class Q7ComboBox(QComboBox): def __init__(self, arg): QComboBox.__init__(self, arg) self.actorlist = QListWidget() self.setModel(self.actorlist.model()) self.setView(self.actorlist) self.view().installEventFilter(self) self.parent = None def setParent(self, parent): self.parent = parent def eventFilter(self, o, e): if e.type() == QEvent.KeyPress: # kmod = e.modifiers() kval = e.key() if kval in [Qt.Key_Z]: path = self.actorlist.currentItem().text() actor = self.parent.findPathObject(path) self.parent.changeCurrentActor([path, actor]) return True if kval in [Qt.Key_H]: path = self.actorlist.currentItem().text() actor = self.parent.findPathObject(path) self.parent.changeCurrentActor([path, actor]) self.parent.hideActor(None) return True return QComboBox.eventFilter(self, o, e) def keyPressEvent(self, event): kmod = event.modifiers() kval = event.key() print(kmod, kval)
class FindOptions(QWidget): """Find widget with options""" REGEX_INVALID = "background-color:rgb(255, 175, 90);" find = Signal() stop = Signal() redirect_stdio = Signal(bool) def __init__(self, parent, search_text, search_text_regexp, search_path, exclude, exclude_idx, exclude_regexp, supported_encodings, in_python_path, more_options, case_sensitive, external_path_history): QWidget.__init__(self, parent) if search_path is None: search_path = getcwd() self.path = '' self.project_path = None self.file_path = None self.external_path = None self.external_path_history = external_path_history if not isinstance(search_text, (list, tuple)): search_text = [search_text] if not isinstance(search_path, (list, tuple)): search_path = [search_path] if not isinstance(exclude, (list, tuple)): exclude = [exclude] if not isinstance(external_path_history, (list, tuple)): external_path_history = [external_path_history] self.supported_encodings = supported_encodings # Layout 1 hlayout1 = QHBoxLayout() self.search_text = PatternComboBox(self, search_text, _("Search pattern")) self.edit_regexp = create_toolbutton(self, icon=ima.icon('advanced'), tip=_('Regular expression')) self.case_button = create_toolbutton(self, icon=get_icon("upper_lower.png"), tip=_("Case Sensitive")) self.case_button.setCheckable(True) self.case_button.setChecked(case_sensitive) self.edit_regexp.setCheckable(True) self.edit_regexp.setChecked(search_text_regexp) self.more_widgets = () self.more_options = create_toolbutton(self, toggled=self.toggle_more_options) self.more_options.setCheckable(True) self.more_options.setChecked(more_options) self.ok_button = create_toolbutton(self, text=_("Search"), icon=ima.icon('find'), triggered=lambda: self.find.emit(), tip=_("Start search"), text_beside_icon=True) self.ok_button.clicked.connect(self.update_combos) self.stop_button = create_toolbutton(self, text=_("Stop"), icon=ima.icon('editclear'), triggered=lambda: self.stop.emit(), tip=_("Stop search"), text_beside_icon=True) self.stop_button.setEnabled(False) for widget in [self.search_text, self.edit_regexp, self.case_button, self.ok_button, self.stop_button, self.more_options]: hlayout1.addWidget(widget) # Layout 2 hlayout2 = QHBoxLayout() self.exclude_pattern = PatternComboBox(self, exclude, _("Excluded filenames pattern")) if exclude_idx is not None and exclude_idx >= 0 \ and exclude_idx < self.exclude_pattern.count(): self.exclude_pattern.setCurrentIndex(exclude_idx) self.exclude_regexp = create_toolbutton(self, icon=ima.icon('advanced'), tip=_('Regular expression')) self.exclude_regexp.setCheckable(True) self.exclude_regexp.setChecked(exclude_regexp) exclude_label = QLabel(_("Exclude:")) exclude_label.setBuddy(self.exclude_pattern) for widget in [exclude_label, self.exclude_pattern, self.exclude_regexp]: hlayout2.addWidget(widget) # Layout 3 hlayout3 = QHBoxLayout() search_on_label = QLabel(_("Search in:")) self.path_selection_combo = PatternComboBox(self, exclude, _('Search directory')) self.path_selection_combo.setEditable(False) self.path_selection_contents = QListWidget(self.path_selection_combo) self.path_selection_contents.hide() self.path_selection_combo.setModel( self.path_selection_contents.model()) self.path_selection_contents.addItem(_("Current working directory")) item = self.path_selection_contents.item(0) item.setToolTip(_("Search in all files and " "directories present on the" "current Spyder path")) self.path_selection_contents.addItem(_("Project")) item = self.path_selection_contents.item(1) item.setToolTip(_("Search in all files and " "directories present on the" "current project path " "(If opened)")) item.setFlags(item.flags() & ~Qt.ItemIsEnabled) self.path_selection_contents.addItem(_("File").replace('&', '')) item = self.path_selection_contents.item(2) item.setToolTip(_("Search in current opened file")) self.path_selection_contents.addItem(_("Select other directory")) item = self.path_selection_contents.item(3) item.setToolTip(_("Search in other folder present on the file system")) self.path_selection_combo.insertSeparator(3) self.path_selection_combo.insertSeparator(5) for path in external_path_history: item = ExternalPathItem(None, path) self.path_selection_contents.addItem(item) self.path_selection_combo.currentIndexChanged.connect( self.path_selection_changed) hlayout3.addWidget(search_on_label) hlayout3.addWidget(self.path_selection_combo) self.search_text.valid.connect(lambda valid: self.find.emit()) self.exclude_pattern.valid.connect(lambda valid: self.find.emit()) vlayout = QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) vlayout.addLayout(hlayout1) vlayout.addLayout(hlayout2) vlayout.addLayout(hlayout3) self.more_widgets = (hlayout2,) self.toggle_more_options(more_options) self.setLayout(vlayout) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) @Slot(bool) def toggle_more_options(self, state): for layout in self.more_widgets: for index in range(layout.count()): if state and self.isVisible() or not state: layout.itemAt(index).widget().setVisible(state) if state: icon = ima.icon('options_less') tip = _('Hide advanced options') else: icon = ima.icon('options_more') tip = _('Show advanced options') self.more_options.setIcon(icon) self.more_options.setToolTip(tip) @Slot() def path_selection_changed(self): idx = self.path_selection_combo.currentIndex() if idx == EXTERNAL_PATH: external_path = self.select_directory() if len(external_path) > 0: item = ExternalPathItem(None, external_path) self.path_selection_contents.addItem(item) total_items = (self.path_selection_combo.count() - MAX_PATH_HISTORY) for i in range(6, total_items): self.path_selection_contents.takeItem(i) self.path_selection_combo.setCurrentIndex( self.path_selection_combo.count() - 1) else: self.path_selection_combo.setCurrentIndex(CWD) elif idx > EXTERNAL_PATH: item = self.path_selection_contents.item(idx) self.external_path = item.path def update_combos(self): self.search_text.lineEdit().returnPressed.emit() self.exclude_pattern.lineEdit().returnPressed.emit() def set_search_text(self, text): if text: self.search_text.add_text(text) self.search_text.lineEdit().selectAll() self.search_text.setFocus() def get_options(self, all=False): # Getting options self.search_text.lineEdit().setStyleSheet("") self.exclude_pattern.lineEdit().setStyleSheet("") utext = to_text_string(self.search_text.currentText()) if not utext: return try: texts = [(utext.encode('utf-8'), 'utf-8')] except UnicodeEncodeError: texts = [] for enc in self.supported_encodings: try: texts.append((utext.encode(enc), enc)) except UnicodeDecodeError: pass text_re = self.edit_regexp.isChecked() exclude = to_text_string(self.exclude_pattern.currentText()) exclude_re = self.exclude_regexp.isChecked() case_sensitive = self.case_button.isChecked() python_path = False if not case_sensitive: texts = [(text[0].lower(), text[1]) for text in texts] file_search = False selection_idx = self.path_selection_combo.currentIndex() if selection_idx == CWD: path = self.path elif selection_idx == PROJECT: path = self.project_path elif selection_idx == FILE_PATH: path = self.file_path file_search = True else: path = self.external_path # Finding text occurrences if not exclude_re: exclude = fnmatch.translate(exclude) else: try: exclude = re.compile(exclude) except Exception: exclude_edit = self.exclude_pattern.lineEdit() exclude_edit.setStyleSheet(self.REGEX_INVALID) return None if text_re: try: texts = [(re.compile(x[0]), x[1]) for x in texts] except Exception: self.search_text.lineEdit().setStyleSheet(self.REGEX_INVALID) return None if all: search_text = [to_text_string(self.search_text.itemText(index)) for index in range(self.search_text.count())] exclude = [to_text_string(self.exclude_pattern.itemText(index)) for index in range(self.exclude_pattern.count())] path_history = [to_text_string( self.path_selection_contents.item(index)) for index in range( 6, self.path_selection_combo.count())] exclude_idx = self.exclude_pattern.currentIndex() more_options = self.more_options.isChecked() return (search_text, text_re, [], exclude, exclude_idx, exclude_re, python_path, more_options, case_sensitive, path_history) else: return (path, file_search, exclude, texts, text_re, case_sensitive) @Slot() def select_directory(self): """Select directory""" self.redirect_stdio.emit(False) directory = getexistingdirectory(self, _("Select directory"), self.path) if directory: directory = to_text_string(osp.abspath(to_text_string(directory))) self.redirect_stdio.emit(True) return directory def set_directory(self, directory): self.path = to_text_string(osp.abspath(to_text_string(directory))) def set_project_path(self, path): self.project_path = to_text_string(osp.abspath(to_text_string(path))) item = self.path_selection_contents.item(PROJECT) item.setFlags(item.flags() | Qt.ItemIsEnabled) def disable_project_search(self): item = self.path_selection_contents.item(PROJECT) item.setFlags(item.flags() & ~Qt.ItemIsEnabled) self.project_path = None def set_file_path(self, path): self.file_path = path def keyPressEvent(self, event): """Reimplemented to handle key events""" ctrl = event.modifiers() & Qt.ControlModifier shift = event.modifiers() & Qt.ShiftModifier if event.key() in (Qt.Key_Enter, Qt.Key_Return): self.find.emit() elif event.key() == Qt.Key_F and ctrl and shift: # Toggle find widgets self.parent().toggle_visibility.emit(not self.isVisible()) else: QWidget.keyPressEvent(self, event)
class FindOptions(QWidget): """Find widget with options""" REGEX_INVALID = "background-color:rgb(255, 175, 90);" find = Signal() stop = Signal() def __init__(self, parent, search_text, search_text_regexp, search_path, exclude, exclude_idx, exclude_regexp, supported_encodings, in_python_path, more_options, case_sensitive, external_path_history): QWidget.__init__(self, parent) if search_path is None: search_path = getcwd_or_home() self.path = '' self.project_path = None self.file_path = None self.external_path = None self.external_path_history = external_path_history if not isinstance(search_text, (list, tuple)): search_text = [search_text] if not isinstance(search_path, (list, tuple)): search_path = [search_path] if not isinstance(exclude, (list, tuple)): exclude = [exclude] if not isinstance(external_path_history, (list, tuple)): external_path_history = [external_path_history] self.supported_encodings = supported_encodings # Layout 1 hlayout1 = QHBoxLayout() self.search_text = PatternComboBox(self, search_text, _("Search pattern")) self.edit_regexp = create_toolbutton(self, icon=ima.icon('advanced'), tip=_('Regular expression')) self.case_button = create_toolbutton(self, icon=get_icon("upper_lower.png"), tip=_("Case Sensitive")) self.case_button.setCheckable(True) self.case_button.setChecked(case_sensitive) self.edit_regexp.setCheckable(True) self.edit_regexp.setChecked(search_text_regexp) self.more_widgets = () self.more_options = create_toolbutton(self, toggled=self.toggle_more_options) self.more_options.setCheckable(True) self.more_options.setChecked(more_options) self.ok_button = create_toolbutton(self, text=_("Search"), icon=ima.icon('find'), triggered=lambda: self.find.emit(), tip=_("Start search"), text_beside_icon=True) self.ok_button.clicked.connect(self.update_combos) self.stop_button = create_toolbutton( self, text=_("Stop"), icon=ima.icon('editclear'), triggered=lambda: self.stop.emit(), tip=_("Stop search"), text_beside_icon=True) self.stop_button.setEnabled(False) for widget in [ self.search_text, self.edit_regexp, self.case_button, self.ok_button, self.stop_button, self.more_options ]: hlayout1.addWidget(widget) # Layout 2 hlayout2 = QHBoxLayout() self.exclude_pattern = PatternComboBox(self, exclude, _("Excluded filenames pattern")) if exclude_idx is not None and exclude_idx >= 0 \ and exclude_idx < self.exclude_pattern.count(): self.exclude_pattern.setCurrentIndex(exclude_idx) self.exclude_regexp = create_toolbutton(self, icon=ima.icon('advanced'), tip=_('Regular expression')) self.exclude_regexp.setCheckable(True) self.exclude_regexp.setChecked(exclude_regexp) exclude_label = QLabel(_("Exclude:")) exclude_label.setBuddy(self.exclude_pattern) for widget in [ exclude_label, self.exclude_pattern, self.exclude_regexp ]: hlayout2.addWidget(widget) # Layout 3 hlayout3 = QHBoxLayout() search_on_label = QLabel(_("Search in:")) self.path_selection_combo = PatternComboBox(self, exclude, _('Search directory')) self.path_selection_combo.setEditable(False) self.path_selection_contents = QListWidget(self.path_selection_combo) self.path_selection_contents.hide() self.path_selection_combo.setModel( self.path_selection_contents.model()) self.path_selection_contents.addItem(_("Current working directory")) item = self.path_selection_contents.item(0) item.setToolTip( _("Search in all files and " "directories present on the" "current Spyder path")) self.path_selection_contents.addItem(_("Project")) item = self.path_selection_contents.item(1) item.setToolTip( _("Search in all files and " "directories present on the" "current project path " "(If opened)")) item.setFlags(item.flags() & ~Qt.ItemIsEnabled) self.path_selection_contents.addItem(_("File").replace('&', '')) item = self.path_selection_contents.item(2) item.setToolTip(_("Search in current opened file")) self.path_selection_contents.addItem(_("Select other directory")) item = self.path_selection_contents.item(3) item.setToolTip(_("Search in other folder present on the file system")) self.path_selection_combo.insertSeparator(3) self.path_selection_combo.insertSeparator(5) for path in external_path_history: item = ExternalPathItem(None, path) self.path_selection_contents.addItem(item) self.path_selection_combo.currentIndexChanged.connect( self.path_selection_changed) hlayout3.addWidget(search_on_label) hlayout3.addWidget(self.path_selection_combo) self.search_text.valid.connect(lambda valid: self.find.emit()) self.exclude_pattern.valid.connect(lambda valid: self.find.emit()) vlayout = QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) vlayout.addLayout(hlayout1) vlayout.addLayout(hlayout2) vlayout.addLayout(hlayout3) self.more_widgets = (hlayout2, ) self.toggle_more_options(more_options) self.setLayout(vlayout) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) @Slot(bool) def toggle_more_options(self, state): for layout in self.more_widgets: for index in range(layout.count()): if state and self.isVisible() or not state: layout.itemAt(index).widget().setVisible(state) if state: icon = ima.icon('options_less') tip = _('Hide advanced options') else: icon = ima.icon('options_more') tip = _('Show advanced options') self.more_options.setIcon(icon) self.more_options.setToolTip(tip) @Slot() def path_selection_changed(self): idx = self.path_selection_combo.currentIndex() if idx == EXTERNAL_PATH: external_path = self.select_directory() if len(external_path) > 0: item = ExternalPathItem(None, external_path) self.path_selection_contents.addItem(item) total_items = (self.path_selection_combo.count() - MAX_PATH_HISTORY) for i in range(6, total_items): self.path_selection_contents.takeItem(i) self.path_selection_combo.setCurrentIndex( self.path_selection_combo.count() - 1) else: self.path_selection_combo.setCurrentIndex(CWD) elif idx > EXTERNAL_PATH: item = self.path_selection_contents.item(idx) self.external_path = item.path def update_combos(self): self.search_text.lineEdit().returnPressed.emit() self.exclude_pattern.lineEdit().returnPressed.emit() def set_search_text(self, text): if text: self.search_text.add_text(text) self.search_text.lineEdit().selectAll() self.search_text.setFocus() def get_options(self, all=False): # Getting options self.search_text.lineEdit().setStyleSheet("") self.exclude_pattern.lineEdit().setStyleSheet("") utext = to_text_string(self.search_text.currentText()) if not utext: return try: texts = [(utext.encode('utf-8'), 'utf-8')] except UnicodeEncodeError: texts = [] for enc in self.supported_encodings: try: texts.append((utext.encode(enc), enc)) except UnicodeDecodeError: pass text_re = self.edit_regexp.isChecked() exclude = to_text_string(self.exclude_pattern.currentText()) exclude_re = self.exclude_regexp.isChecked() case_sensitive = self.case_button.isChecked() python_path = False if not case_sensitive: texts = [(text[0].lower(), text[1]) for text in texts] file_search = False selection_idx = self.path_selection_combo.currentIndex() if selection_idx == CWD: path = self.path elif selection_idx == PROJECT: path = self.project_path elif selection_idx == FILE_PATH: path = self.file_path file_search = True else: path = self.external_path # Finding text occurrences if not exclude_re: exclude = fnmatch.translate(exclude) else: try: exclude = re.compile(exclude) except Exception: exclude_edit = self.exclude_pattern.lineEdit() exclude_edit.setStyleSheet(self.REGEX_INVALID) return None if text_re: try: texts = [(re.compile(x[0]), x[1]) for x in texts] except Exception: self.search_text.lineEdit().setStyleSheet(self.REGEX_INVALID) return None if all: search_text = [ to_text_string(self.search_text.itemText(index)) for index in range(self.search_text.count()) ] exclude = [ to_text_string(self.exclude_pattern.itemText(index)) for index in range(self.exclude_pattern.count()) ] path_history = [ to_text_string(self.path_selection_contents.item(index)) for index in range(6, self.path_selection_combo.count()) ] exclude_idx = self.exclude_pattern.currentIndex() more_options = self.more_options.isChecked() return (search_text, text_re, [], exclude, exclude_idx, exclude_re, python_path, more_options, case_sensitive, path_history) else: return (path, file_search, exclude, texts, text_re, case_sensitive) @Slot() def select_directory(self): """Select directory""" self.parent().redirect_stdio.emit(False) directory = getexistingdirectory(self, _("Select directory"), self.path) if directory: directory = to_text_string(osp.abspath(to_text_string(directory))) self.parent().redirect_stdio.emit(True) return directory def set_directory(self, directory): self.path = to_text_string(osp.abspath(to_text_string(directory))) def set_project_path(self, path): self.project_path = to_text_string(osp.abspath(to_text_string(path))) item = self.path_selection_contents.item(PROJECT) item.setFlags(item.flags() | Qt.ItemIsEnabled) def disable_project_search(self): item = self.path_selection_contents.item(PROJECT) item.setFlags(item.flags() & ~Qt.ItemIsEnabled) self.project_path = None def set_file_path(self, path): self.file_path = path def keyPressEvent(self, event): """Reimplemented to handle key events""" ctrl = event.modifiers() & Qt.ControlModifier shift = event.modifiers() & Qt.ShiftModifier if event.key() in (Qt.Key_Enter, Qt.Key_Return): self.find.emit() elif event.key() == Qt.Key_F and ctrl and shift: # Toggle find widgets self.parent().toggle_visibility.emit(not self.isVisible()) else: QWidget.keyPressEvent(self, event)
class HeaderEditDialog(QDialog): # name of the current preset; whether to set this preset as default; list of Columns header_changed = Signal(str, bool, list) def __init__(self, parent, table_header): super().__init__(parent) self.table_header = table_header self.default_preset_name = None self.preset_name = table_header.preset_name self.columns = deepcopy(table_header.columns) self.setupUi() self.update_output() def setupUi(self): self.resize(240, 400) self.vbox = QVBoxLayout(self) self.presetLabel = QLabel(self) self.columnList = QListWidget(self) self.setAsDefaultCheckbox = QCheckBox("Set as default preset", self) self.vbox.addWidget(self.presetLabel) self.vbox.addWidget(self.columnList) self.vbox.addWidget(self.setAsDefaultCheckbox) self.columnList.setDragDropMode(QListWidget.InternalMove) self.columnList.setDefaultDropAction(Qt.MoveAction) self.columnList.setSelectionMode(QListWidget.ExtendedSelection) self.columnList.setAlternatingRowColors(True) self.columnList.installEventFilter(self) self.columnList.setContextMenuPolicy(Qt.CustomContextMenu) self.columnList.customContextMenuRequested.connect(self.open_menu) self.columnList.model().rowsMoved.connect(self.read_columns_from_list) # for a dumb qss hack to make selected checkboxes not white on a light theme self.columnList.setObjectName("ColumnList") buttons = QDialogButtonBox.Reset | QDialogButtonBox.Save | QDialogButtonBox.Cancel self.buttonBox = QDialogButtonBox(buttons, self) self.vbox.addWidget(self.buttonBox) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.resetButton = self.buttonBox.button(QDialogButtonBox.Reset) self.resetButton.clicked.connect(self.reset_to_stock) def eventFilter(self, object, event): if event.type() == QEvent.KeyPress: if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return: self.toggle_selected_columns() return True if event.key() == Qt.Key_Delete: self.delete_selected() return True return False def update_output(self): self.presetLabel.setText("Preset: {}".format(self.preset_name)) self.setAsDefaultCheckbox.setChecked( CONFIG['default_header_preset'] == self.preset_name) self.columnList.clear() for column in self.columns: ColumnListItem(self.columnList, column) def accept(self): self.read_columns_from_list() self.header_changed.emit(self.preset_name, self.setAsDefaultCheckbox.isChecked(), self.columns) self.done(0) def reject(self): self.done(0) def reset_to_stock(self): self.columns = deepcopy(DEFAULT_COLUMNS) self.update_output() def read_columns_from_list(self): new_columns = [] for i in range(self.columnList.count()): item = self.columnList.item(i) new_columns.append(item.column) self.columns = new_columns def toggle_selected_columns(self): selected = self.columnList.selectedItems() for item in selected: value_now = item.data(Qt.CheckStateRole) item.setData(Qt.CheckStateRole, not value_now) self.columnList.reset( ) # @Improvement: is there a better way to update QListWidget? def open_menu(self, position): menu = QMenu(self) preset_menu = menu.addMenu('Presets') preset_menu.addAction('New preset', self.new_preset_dialog) preset_menu.addSeparator() preset_names = CONFIG.get_header_presets() if len(preset_names) == 0: action = preset_menu.addAction('No presets') action.setEnabled(False) else: delete_menu = menu.addMenu('Delete preset') for name in preset_names: preset_menu.addAction(name, partial(self.load_preset, name)) delete_menu.addAction(name, partial(self.delete_preset, name)) menu.addSeparator() menu.addAction('New column...', self.create_new_column_dialog) if len(self.columnList.selectedIndexes()) > 0: menu.addAction('Delete selected', self.delete_selected) menu.popup(self.columnList.viewport().mapToGlobal(position)) def load_preset(self, name): new_columns = CONFIG.load_header_preset(name) if not new_columns: return self.columns = new_columns self.preset_name = name self.update_output() def new_preset_dialog(self): d = QInputDialog(self) d.setLabelText('Enter the new name for the new preset:') d.setWindowTitle('Create new preset') d.textValueSelected.connect(self.create_new_preset) d.open() def create_new_preset(self, name): if name in CONFIG.get_header_presets(): show_warning_dialog( self, "Preset creation error", 'Preset named "{}" already exists.'.format(name)) return if len(name.strip()) == 0: show_warning_dialog( self, "Preset creation error", 'This preset name is not allowed.'.format(name)) return self.preset_name = name self.update_output() CONFIG.save_header_preset(name, self.columns) def delete_preset(self, name): CONFIG.delete_header_preset(name) if name == self.preset_name: self.columns = deepcopy(DEFAULT_COLUMNS) self.update_output() def create_new_column_dialog(self): d = CreateNewColumnDialog(self) d.add_new_column.connect(self.add_new_column) d.setWindowTitle('Create new column') d.open() def add_new_column(self, name, title): new_column = Column(name, title) # if the last column is message, insert this column before it (I think that makes sense?) if len(self.columns) == 0: self.columns.append(new_column) elif self.columns[-1].name in ('message', 'msg'): self.columns.insert(-1, new_column) else: self.columns.append(new_column) self.update_output() def delete_selected(self): selected = self.columnList.selectedItems() for item in selected: self.columnList.takeItem(self.columnList.row(item)) self.read_columns_from_list() self.update_output()