class SFeaturesViewer(QWidget): """Widget to display a the tracks features table Parameters ---------- napari_viewer: QWidget The napari viewer """ def __init__(self, napari_viewer): super().__init__() self.viewer = napari_viewer self.layer_name = '' layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.tableWidget = QTableWidget() self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) layout.addWidget(self.tableWidget) self.setLayout(layout) def reload(self): """Reload the tracks features from the layers to the table widget""" particles = self.viewer.layers[self.layer_name].data features = self.viewer.layers[self.layer_name].metadata headers = ['track_id'] for key in features: if isinstance(features[key], dict): headers.append(key) self.tableWidget.setColumnCount(len(headers)) self.tableWidget.setHorizontalHeaderLabels(headers) self.tableWidget.setRowCount(len(np.unique(particles[:, 0]))) features_dict = dict() tracks_ids = np.unique(particles[:, 0]) for id_ in tracks_ids: features_dict[id_] = list() for key in features: if isinstance(features[key], dict): feature_dict = features[key] for f_key in feature_dict: if f_key in features_dict: features_dict[f_key].append(str(feature_dict[f_key])) line = -1 for key in features_dict: line += 1 # track_id = key self.tableWidget.setItem(line, 0, QTableWidgetItem(str(key))) # add each feature per column col = 0 for feature in features_dict[key]: col += 1 self.tableWidget.setItem(line, col, QTableWidgetItem(feature))
def create_page_game(self): widget = QTableWidget() widget.setEditTriggers(QAbstractItemView.NoEditTriggers) widget.setSortingEnabled(True) widget.setRowCount(1000) widget.setColumnCount(len(GAME_LIST)) widget.setHorizontalHeaderLabels(GAME_LIST) header = widget.horizontalHeader() for i in range(len(GAME_LIST)): header.setSectionResizeMode(i, QHeaderView.ResizeToContents) return widget
def create_page_rank(self): widget = QTableWidget() widget.setEditTriggers(QAbstractItemView.NoEditTriggers) widget.setSortingEnabled(True) widget.setRowCount(20) widget.setColumnCount(len(RANK_LIST)) widget.setHorizontalHeaderLabels(RANK_LIST) header = widget.horizontalHeader() for i in range(len(RANK_LIST)): header.setSectionResizeMode(i, QHeaderView.ResizeToContents) widget.horizontalHeader().sortIndicatorChanged.connect( self.update_chart) return widget
def _make_table_widget(self): """ Make a table showing the matplotlib figure number of the plots, the name with close and edit buttons, and a hidden column for sorting with the last actuve order :return: A QTableWidget object which will contain plot widgets """ table_widget = QTableWidget(0, 3, self) table_widget.setHorizontalHeaderLabels( ['No.', 'Plot Name', 'Last Active Order (hidden)']) table_widget.verticalHeader().setVisible(False) # Fix the size of 'No.' and let 'Plot Name' fill the space top_header = table_widget.horizontalHeader() table_widget.horizontalHeaderItem(Column.Number).setToolTip( 'This is the matplotlib figure number.\n\nFrom a ' 'script use plt.figure(N), where N is this figure ' 'number, to get a handle to the plot.') table_widget.horizontalHeaderItem(Column.Name).setToolTip( 'The plot name, also used as the file name when ' 'saving multiple plots.') table_widget.setSelectionBehavior(QAbstractItemView.SelectRows) table_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) table_widget.setEditTriggers(QAbstractItemView.NoEditTriggers) table_widget.sortItems(Column.Number, Qt.AscendingOrder) table_widget.setSortingEnabled(True) table_widget.horizontalHeader().sectionClicked.connect( self.update_sort_menu_selection) if not DEBUG_MODE: table_widget.setColumnHidden(Column.LastActive, True) top_header.resizeSection(Column.Number, top_header.sectionSizeHint(Column.Number)) top_header.setSectionResizeMode(Column.Name, QHeaderView.Stretch) return table_widget
def _make_table_widget(self): """ Make a table showing the matplotlib figure number of the plots, the name with close and edit buttons, and a hidden column for sorting with the last actuve order :return: A QTableWidget object which will contain plot widgets """ table_widget = QTableWidget(0, 3, self) table_widget.setHorizontalHeaderLabels(['No.', 'Plot Name', 'Last Active Order (hidden)']) table_widget.verticalHeader().setVisible(False) # Fix the size of 'No.' and let 'Plot Name' fill the space top_header = table_widget.horizontalHeader() table_widget.horizontalHeaderItem(Column.Number).setToolTip('This is the matplotlib figure number.\n\nFrom a ' 'script use plt.figure(N), where N is this figure ' 'number, to get a handle to the plot.') table_widget.horizontalHeaderItem(Column.Name).setToolTip('The plot name, also used as the file name when ' 'saving multiple plots.') table_widget.setSelectionBehavior(QAbstractItemView.SelectRows) table_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) table_widget.setEditTriggers(QAbstractItemView.NoEditTriggers) table_widget.sortItems(Column.Number, Qt.AscendingOrder) table_widget.setSortingEnabled(True) table_widget.horizontalHeader().sectionClicked.connect(self.update_sort_menu_selection) if not DEBUG_MODE: table_widget.setColumnHidden(Column.LastActive, True) top_header.resizeSection(Column.Number, top_header.sectionSizeHint(Column.Number)) top_header.setSectionResizeMode(Column.Name, QHeaderView.Stretch) return table_widget
class SPropertiesViewer(QWidget): """Widget to display a the particles properties table Parameters ---------- napari_viewer: QWidget The napari viewer """ def __init__(self, napari_viewer): super().__init__() self.viewer = napari_viewer self.layer_name = '' layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.tableWidget = QTableWidget() self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) layout.addWidget(self.tableWidget) self.setLayout(layout) def reload(self): """Reload the particles properties from the layers to the table widget""" particles = self.viewer.layers[self.layer_name].data print(particles) properties = self.viewer.layers[self.layer_name].properties headers = [] if particles.shape[1] == 3: headers = ['T', 'Y', 'X'] elif particles.shape[1] == 4: headers = ['T', 'Z', 'Y', 'X'] for key in properties: headers.append(key) self.tableWidget.setColumnCount(len(headers)) self.tableWidget.setHorizontalHeaderLabels(headers) self.tableWidget.setRowCount(particles.shape[0]) col = 0 for line in range(particles.shape[0]): col = -1 # T if particles.shape[1] == 4: col += 1 self.tableWidget.setItem(line, col, QTableWidgetItem( str(particles[line, col]))) # T or Z if particles.shape[1] >= 3: col += 1 self.tableWidget.setItem(line, col, QTableWidgetItem( str(particles[line, col]))) # Y col += 1 self.tableWidget.setItem(line, col, QTableWidgetItem( str(particles[line, col]))) # X col += 1 self.tableWidget.setItem(line, col, QTableWidgetItem( str(particles[line, col]))) # properties for key in properties: col += 1 prop = properties[key] for line in range(len(prop)): self.tableWidget.setItem(line, col, QTableWidgetItem(str(prop[line])))
class LogViewerDialog(DialogBase): """Logger widget.""" def __init__( self, parent=None, log_folder=LOG_FOLDER, log_filename=LOG_FILENAME, ): """ Logger widget. Parameters ---------- log_folder: str Folder where logs are located log_filename: str Basic name for the rotating log files. """ super(LogViewerDialog, self).__init__(parent=parent) self._data = None self._columns = ['level', 'time', 'module', 'method', 'message'] self._headers = [c.capitalize() for c in self._columns] self._log_filename = log_filename self._log_folder = log_folder # Widgets self.label = QLabel('Select log file:') self.combobox = ComboBoxBase() self.table_logs = QTableWidget(self) self.button_copy = ButtonPrimary('Copy') self.text_search = LineEditSearch() # Widget setup self.table_logs.setAttribute(Qt.WA_LayoutUsesWidgetRect, True) horizontal_header = self.table_logs.horizontalHeader() vertical_header = self.table_logs.verticalHeader() horizontal_header.setStretchLastSection(True) horizontal_header.setSectionResizeMode(QHeaderView.Fixed) vertical_header.setSectionResizeMode(QHeaderView.Fixed) self.table_logs.setSelectionBehavior(QTableWidget.SelectRows) self.table_logs.setEditTriggers(QTableWidget.NoEditTriggers) self.setWindowTitle('Log Viewer') self.setMinimumWidth(800) self.setMinimumHeight(500) self.text_search.setPlaceholderText("Search...") # Layouts top_layout = QHBoxLayout() top_layout.addWidget(self.label) top_layout.addWidget(SpacerHorizontal()) top_layout.addWidget(self.combobox) top_layout.addStretch() top_layout.addWidget(SpacerHorizontal()) top_layout.addWidget(self.text_search) top_layout.addWidget(SpacerHorizontal()) top_layout.addWidget(self.button_copy) layout = QVBoxLayout() layout.addLayout(top_layout) layout.addWidget(SpacerVertical()) layout.addWidget(self.table_logs) self.setLayout(layout) # Signals self.combobox.currentIndexChanged.connect(self.update_text) self.button_copy.clicked.connect(self.copy_item) self.text_search.textChanged.connect(self.filter_text) # Setup() self.setup() self.update_style_sheet() def update_style_sheet(self, style_sheet=None): """Update custom CSS stylesheet.""" if style_sheet is None: style_sheet = load_style_sheet() self.setStyleSheet(style_sheet) def setup(self): """Setup widget content.""" self.combobox.clear() paths = log_files( log_folder=self._log_folder, log_filename=self._log_filename, ) files = [os.path.basename(p) for p in paths] self.combobox.addItems(files) def filter_text(self): """Search for text in the selected log file.""" search = self.text_search.text().lower() for i, data in enumerate(self._data): if any(search in str(d).lower() for d in data.values()): self.table_logs.showRow(i) else: self.table_logs.hideRow(i) def row_data(self, row): """Give the current row data concatenated with spaces.""" data = {} if self._data: length = len(self._data) if 0 >= row < length: data = self._data[row] return data def update_text(self, index): """Update logs based on combobox selection.""" path = os.path.join(self._log_folder, self.combobox.currentText()) self._data = load_log(path) self.table_logs.clear() self.table_logs.setSortingEnabled(False) self.table_logs.setRowCount(len(self._data)) self.table_logs.setColumnCount(len(self._columns)) self.table_logs.setHorizontalHeaderLabels(self._headers) for row, data in enumerate(self._data): for col, col_key in enumerate(self._columns): item = QTableWidgetItem(data.get(col_key, '')) self.table_logs.setItem(row, col, item) for c in [0, 2, 3]: self.table_logs.resizeColumnToContents(c) self.table_logs.resizeRowsToContents() self.table_logs.setSortingEnabled(True) self.table_logs.scrollToBottom() self.table_logs.scrollToTop() self.table_logs.sortByColumn(1, Qt.AscendingOrder) # Make sure there is always a selected row self.table_logs.setCurrentCell(0, 0) def copy_item(self): """Copy selected item to clipboard in markdown format.""" app = QApplication.instance() items = self.table_logs.selectedIndexes() if items: rows = set(sorted(i.row() for i in items)) if self._data: all_data = [self._data[row] for row in rows] dump = json.dumps(all_data, sort_keys=True, indent=4) app.clipboard().setText('```json\n' + dump + '\n```')
class MeasurementWidget(QWidget): """ :type settings: Settings :type segment: Segment """ def __init__(self, settings: PartSettings, segment=None): super().__init__() self.settings = settings self.segment = segment self.measurements_storage = MeasurementsStorage() self.recalculate_button = QPushButton( "Recalculate and\n replace measurement", self) self.recalculate_button.clicked.connect( self.replace_measurement_result) self.recalculate_append_button = QPushButton( "Recalculate and\n append measurement", self) self.recalculate_append_button.clicked.connect( self.append_measurement_result) self.copy_button = QPushButton("Copy to clipboard", self) self.copy_button.setToolTip( "You cacn copy also with 'Ctrl+C'. To get raw copy copy with 'Ctrl+Shit+C'" ) self.horizontal_measurement_present = QCheckBox( "Horizontal view", self) self.no_header = QCheckBox("No header", self) self.no_units = QCheckBox("No units", self) self.no_units.setChecked(True) self.no_units.clicked.connect(self.refresh_view) self.expand_mode = QCheckBox("Expand", self) self.expand_mode.setToolTip( "Shows results for each component in separate entry") self.file_names = EnumComboBox(FileNamesEnum) self.file_names_label = QLabel("Add file name:") self.file_names.currentIndexChanged.connect(self.refresh_view) self.horizontal_measurement_present.stateChanged.connect( self.refresh_view) self.expand_mode.stateChanged.connect(self.refresh_view) self.copy_button.clicked.connect(self.copy_to_clipboard) self.measurement_type = SearchCombBox(self) # noinspection PyUnresolvedReferences self.measurement_type.currentIndexChanged.connect( self.measurement_profile_selection_changed) self.measurement_type.addItem("<none>") self.measurement_type.addItems( list(sorted(self.settings.measurement_profiles.keys()))) self.measurement_type.setToolTip( 'You can create new measurement profile in advanced window, in tab "Measurement settings"' ) self.channels_chose = ChannelComboBox() self.units_choose = EnumComboBox(Units) self.units_choose.set_value(self.settings.get("units_value", Units.nm)) self.info_field = QTableWidget(self) self.info_field.setColumnCount(3) self.info_field.setHorizontalHeaderLabels(["Name", "Value", "Units"]) self.measurement_add_shift = 0 layout = QVBoxLayout() # layout.addWidget(self.recalculate_button) v_butt_layout = QVBoxLayout() v_butt_layout.setSpacing(1) self.up_butt_layout = QHBoxLayout() self.up_butt_layout.addWidget(self.recalculate_button) self.up_butt_layout.addWidget(self.recalculate_append_button) self.butt_layout = QHBoxLayout() # self.butt_layout.setMargin(0) # self.butt_layout.setSpacing(10) self.butt_layout.addWidget(self.horizontal_measurement_present, 1) self.butt_layout.addWidget(self.no_header, 1) self.butt_layout.addWidget(self.no_units, 1) self.butt_layout.addWidget(self.expand_mode, 1) self.butt_layout.addWidget(self.file_names_label) self.butt_layout.addWidget(self.file_names, 1) self.butt_layout.addWidget(self.copy_button, 2) self.butt_layout2 = QHBoxLayout() self.butt_layout3 = QHBoxLayout() self.butt_layout3.addWidget(QLabel("Channel:")) self.butt_layout3.addWidget(self.channels_chose) self.butt_layout3.addWidget(QLabel("Units:")) self.butt_layout3.addWidget(self.units_choose) # self.butt_layout3.addWidget(QLabel("Noise removal:")) # self.butt_layout3.addWidget(self.noise_removal_method) self.butt_layout3.addWidget(QLabel("Measurement set:")) self.butt_layout3.addWidget(self.measurement_type, 2) v_butt_layout.addLayout(self.up_butt_layout) v_butt_layout.addLayout(self.butt_layout) v_butt_layout.addLayout(self.butt_layout2) v_butt_layout.addLayout(self.butt_layout3) layout.addLayout(v_butt_layout) # layout.addLayout(self.butt_layout) layout.addWidget(self.info_field) self.setLayout(layout) # noinspection PyArgumentList self.clip = QApplication.clipboard() self.settings.image_changed[int].connect(self.image_changed) self.previous_profile = None def check_if_measurement_can_be_calculated(self, name): if name == "<none>": return "<none>" profile: MeasurementProfile = self.settings.measurement_profiles.get( name) if profile.is_any_mask_measurement() and self.settings.mask is None: QMessageBox.information( self, "Need mask", "To use this measurement set please use data with mask loaded", QMessageBox.Ok) self.measurement_type.setCurrentIndex(0) return "<none>" if self.settings.roi is None: QMessageBox.information( self, "Need segmentation", 'Before calculating please create segmentation ("Execute" button)', QMessageBox.Ok, ) self.measurement_type.setCurrentIndex(0) return "<none>" return name def image_changed(self, channels_num): self.channels_chose.change_channels_num(channels_num) def measurement_profile_selection_changed(self, index): text = self.measurement_type.itemText(index) text = self.check_if_measurement_can_be_calculated(text) try: stat = self.settings.measurement_profiles[text] is_mask = stat.is_any_mask_measurement() disable = is_mask and (self.settings.mask is None) except KeyError: disable = True self.recalculate_button.setDisabled(disable) self.recalculate_append_button.setDisabled(disable) if disable: self.recalculate_button.setToolTip( "Measurement profile contains mask measurements when mask is not loaded" ) self.recalculate_append_button.setToolTip( "Measurement profile contains mask measurements when mask is not loaded" ) else: self.recalculate_button.setToolTip("") self.recalculate_append_button.setToolTip("") def copy_to_clipboard(self): s = "" for r in range(self.info_field.rowCount()): for c in range(self.info_field.columnCount()): try: s += str(self.info_field.item(r, c).text()) + "\t" except AttributeError: s += "\t" s = s[:-1] + "\n" # eliminate last '\t' self.clip.setText(s) def replace_measurement_result(self): self.measurements_storage.clear() self.previous_profile = "" self.append_measurement_result() def refresh_view(self): self.measurements_storage.set_expand(self.expand_mode.isChecked()) self.measurements_storage.set_show_units(not self.no_units.isChecked()) self.info_field.clear() save_orientation = self.horizontal_measurement_present.isChecked() columns, rows = self.measurements_storage.get_size(save_orientation) self.info_field.setColumnCount(columns) self.info_field.setRowCount(rows) self.info_field.setHorizontalHeaderLabels( self.measurements_storage.get_header(save_orientation)) self.info_field.setVerticalHeaderLabels( self.measurements_storage.get_rows(save_orientation)) for x in range(rows): for y in range(columns): self.info_field.setItem( x, y, QTableWidgetItem( self.measurements_storage.get_val_as_str( x, y, save_orientation))) if self.file_names.get_value() == FileNamesEnum.No: if save_orientation: self.info_field.removeColumn(0) else: self.info_field.removeRow(0) elif self.file_names.get_value() == FileNamesEnum.Short: if save_orientation: columns = 1 else: rows = 1 for x in range(rows): for y in range(columns): item = self.info_field.item(x, y) item.setText(os.path.basename(item.text())) self.info_field.setEditTriggers(QAbstractItemView.NoEditTriggers) def append_measurement_result(self): try: compute_class = self.settings.measurement_profiles[ self.measurement_type.currentText()] except KeyError: QMessageBox.warning( self, "Measurement profile not found", f"Measurement profile '{self.measurement_type.currentText()}' not found'", ) return if self.settings.roi is None: return units = self.units_choose.get_value() # FIXME find which errors should be displayed as warning # def exception_hook(exception): # QMessageBox.warning(self, "Calculation error", f"Error during calculation: {exception}") for num in compute_class.get_channels_num(): if num >= self.settings.image.channels: QMessageBox.warning( self, "Measurement error", "Cannot calculate this measurement because " f"image do not have channel {num+1}", ) return thread = ExecuteFunctionThread( compute_class.calculate, [ self.settings.image, self.channels_chose.currentIndex(), self.settings.roi_info, units ], ) dial = WaitingDialog( thread, "Measurement calculation") # , exception_hook=exception_hook) dial.exec() stat: MeasurementResult = thread.result if stat is None: return stat.set_filename(self.settings.image_path) self.measurements_storage.add_measurements(stat) self.previous_profile = compute_class.name self.refresh_view() def keyPressEvent(self, e: QKeyEvent): if e.modifiers() & Qt.ControlModifier: selected = self.info_field.selectedRanges() if e.key() == Qt.Key_C: # copy s = "" for r in range(selected[0].topRow(), selected[0].bottomRow() + 1): for c in range(selected[0].leftColumn(), selected[0].rightColumn() + 1): try: s += str(self.info_field.item(r, c).text()) + "\t" except AttributeError: s += "\t" s = s[:-1] + "\n" # eliminate last '\t' self.clip.setText(s) def update_measurement_list(self): self.measurement_type.blockSignals(True) available = list(sorted(self.settings.measurement_profiles.keys())) text = self.measurement_type.currentText() try: index = available.index(text) + 1 except ValueError: index = 0 self.measurement_type.clear() self.measurement_type.addItem("<none>") self.measurement_type.addItems(available) self.measurement_type.setCurrentIndex(index) self.measurement_type.blockSignals(False) def showEvent(self, _): self.update_measurement_list() def event(self, event: QEvent): if event.type() == QEvent.WindowActivate: self.update_measurement_list() return super().event(event) @staticmethod def _move_widgets(widgets_list: List[Tuple[QWidget, int]], layout1: QBoxLayout, layout2: QBoxLayout): for el in widgets_list: layout1.removeWidget(el[0]) layout2.addWidget(el[0], el[1]) def resizeEvent(self, _event: QResizeEvent) -> None: if self.width() < 800 and self.butt_layout2.count() == 0: self._move_widgets( [(self.file_names_label, 1), (self.file_names, 1), (self.copy_button, 2)], self.butt_layout, self.butt_layout2, ) elif self.width() > 800 and self.butt_layout2.count() != 0: self._move_widgets( [(self.file_names_label, 1), (self.file_names, 1), (self.copy_button, 2)], self.butt_layout2, self.butt_layout, )
class LevelsPresetDialog(QDialog): # name of the current preset; whether to set this preset as default; dict of Levels levels_changed = Signal(str, bool, dict) def __init__(self, parent, preset_name, levels): super().__init__(parent) self.preset_name = preset_name self.levels = deepcopy(levels) self.setupUi() self.update_output() def setupUi(self): self.resize(480, 340) self.vbox = QVBoxLayout(self) self.presetLabel = QLabel(self) self.table = QTableWidget(0, 4, self) self.setAsDefaultCheckbox = QCheckBox("Set as default preset", self) self.vbox.addWidget(self.presetLabel) self.vbox.addWidget(self.table) self.vbox.addWidget(self.setAsDefaultCheckbox) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.table.setSelectionBehavior(QTableWidget.SelectRows) self.table.setHorizontalHeaderLabels( ["Show", "Level name", "Preview", "Preview (dark)"]) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.table.horizontalHeader().setSectionsClickable(False) self.table.horizontalHeader().setSectionsMovable(False) self.table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.ResizeToContents) self.table.verticalHeader().setVisible(False) self.table.doubleClicked.connect(self.open_level_edit_dialog) self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.open_menu) 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) def update_output(self): self.presetLabel.setText("Preset: {}".format(self.preset_name)) self.setAsDefaultCheckbox.setChecked( CONFIG['default_levels_preset'] == self.preset_name) self.table.clearContents() self.table.setRowCount(len(self.levels)) for i, levelname in enumerate(self.levels): level = self.levels[levelname] checkbox = self.get_level_show_checkbox(level) nameItem = QTableWidgetItem(level.levelname) preview, previewDark = self.get_preview_items(level) self.table.setCellWidget(i, 0, checkbox) self.table.setItem(i, 1, nameItem) self.table.setItem(i, 2, preview) self.table.setItem(i, 3, previewDark) def get_level_show_checkbox(self, level): checkbox_widget = QWidget(self.table) checkbox_widget.setStyleSheet("QWidget { background-color:none;}") checkbox = QCheckBox() checkbox.setStyleSheet( "QCheckBox::indicator { width: 15px; height: 15px;}") checkbox.setChecked(level.enabled) checkbox_layout = QHBoxLayout() checkbox_layout.setAlignment(Qt.AlignCenter) checkbox_layout.setContentsMargins(0, 0, 0, 0) checkbox_layout.addWidget(checkbox) checkbox_widget.setLayout(checkbox_layout) return checkbox_widget def get_preview_items(self, level): previewItem = QTableWidgetItem("Log message") previewItem.setBackground(QBrush(level.bg, Qt.SolidPattern)) previewItem.setForeground(QBrush(level.fg, Qt.SolidPattern)) previewItemDark = QTableWidgetItem("Log message") previewItemDark.setBackground(QBrush(level.bgDark, Qt.SolidPattern)) previewItemDark.setForeground(QBrush(level.fgDark, Qt.SolidPattern)) font = QFont(CONFIG.logger_table_font, CONFIG.logger_table_font_size) fontDark = QFont(font) if 'bold' in level.styles: font.setBold(True) if 'italic' in level.styles: font.setItalic(True) if 'underline' in level.styles: font.setUnderline(True) if 'bold' in level.stylesDark: fontDark.setBold(True) if 'italic' in level.stylesDark: fontDark.setItalic(True) if 'underline' in level.stylesDark: fontDark.setUnderline(True) previewItem.setFont(font) previewItemDark.setFont(fontDark) return previewItem, previewItemDark def open_level_edit_dialog(self, index): levelname = self.table.item(index.row(), 1).data(Qt.DisplayRole) level = self.levels[levelname] d = LevelEditDialog(self, level) d.setWindowModality(Qt.NonModal) d.setWindowTitle('Level editor') d.level_changed.connect(self.update_output) d.open() 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_levels_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 level...', self.create_new_level_dialog) if len(self.table.selectedIndexes()) > 0: menu.addAction('Delete selected', self.delete_selected) menu.popup(self.table.viewport().mapToGlobal(position)) def load_preset(self, name): new_levels = CONFIG.load_levels_preset(name) if not new_levels: return self.levels = new_levels self.preset_name = name self.update_output() def delete_preset(self, name): CONFIG.delete_levels_preset(name) if name == self.preset_name: self.reset() def delete_selected(self): selected = self.table.selectionModel().selectedRows() for index in selected: item = self.table.item(index.row(), 1) del self.levels[item.text()] 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_levels_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_levels_preset(name, self.levels) def create_new_level_dialog(self): d = LevelEditDialog(self, creating_new_level=True, level_names=self.levels.keys()) d.setWindowModality(Qt.NonModal) d.setWindowTitle('Level editor') d.level_changed.connect(self.level_changed) d.open() def level_changed(self, level): if level.levelname in self.levels: self.levels.copy_from(level) else: self.levels[level.levelname] = level self.update_output() def accept(self): for i, _ in enumerate(self.levels): checkbox = self.table.cellWidget(i, 0).children()[1] levelname = self.table.item(i, 1).text() self.levels[levelname].enabled = checkbox.isChecked() self.levels_changed.emit(self.preset_name, self.setAsDefaultCheckbox.isChecked(), self.levels) self.done(0) def reject(self): self.done(0) def reset(self): for levelname, level in self.levels.items(): level.copy_from(get_default_level(levelname)) self.update_output()
class OpticsAdjustSettings(SiriusDialog): """Auxiliar window to optics adjust settings.""" updateSettings = Signal(str, str) def __init__(self, tuneconfig_currname, chromconfig_currname, parent=None): """Initialize object.""" super().__init__(parent) self.setWindowTitle('Optics Adjust Settings') self.setObjectName('BOApp') self.tuneconfig_currname = tuneconfig_currname self.chromconfig_currname = chromconfig_currname self.conn_tuneparams = _ConfigDBClient( config_type='bo_tunecorr_params') self.conn_chromparams = _ConfigDBClient( config_type='bo_chromcorr_params') self._setupUi() def _setupUi(self): self.tune_settings = QWidget(self) self.tune_settings.setLayout(self._setupTuneSettings()) self.le_tuneconfig.setText(self.tuneconfig_currname) self.chrom_settings = QWidget(self) self.chrom_settings.setLayout(self._setupChromSettings()) self.le_chromconfig.setText(self.chromconfig_currname) self.bt_apply = QPushButton('Apply Settings', self) self.bt_apply.setStyleSheet("""min-width:8em; max-width:8em;""") self.bt_apply.clicked.connect(self._emitSettings) self.bt_apply.setAutoDefault(False) self.bt_apply.setDefault(False) hlay_apply = QHBoxLayout() hlay_apply.addItem( QSpacerItem(20, 60, QSzPlcy.Expanding, QSzPlcy.Ignored)) hlay_apply.addWidget(self.bt_apply) tabs = QTabWidget(self) tabs.addTab(self.tune_settings, 'Tune') tabs.addTab(self.chrom_settings, 'Chromaticity') lay = QVBoxLayout() lay.addWidget(tabs) lay.addLayout(hlay_apply) self.setLayout(lay) def _setupTuneSettings(self): l_tuneconfig = QLabel('<h3>Tune Variation Config</h3>', self) l_tuneconfig.setAlignment(Qt.AlignCenter) self.le_tuneconfig = _ConfigLineEdit(parent=self, config_type='bo_tunecorr_params') self.le_tuneconfig.textChanged.connect(self._showTuneConfigData) label_tunemat = QLabel('<h4>Matrix</h4>', self) label_tunemat.setAlignment(Qt.AlignCenter) self.table_tunemat = QTableWidget(self) self.table_tunemat.setObjectName('tunemat') self.table_tunemat.setStyleSheet(""" #tunemat{ background-color: #efebe7; min-width: 22.14em; min-height: 6em; max-height: 6em;}""") self.table_tunemat.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table_tunemat.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_tunemat.setRowCount(2) self.table_tunemat.setColumnCount(2) self.table_tunemat.setVerticalHeaderLabels([' X', ' Y']) self.table_tunemat.setHorizontalHeaderLabels(['QF', 'QD']) self.table_tunemat.horizontalHeader().setStyleSheet(""" min-height:1.55em; max-height:1.55em;""") self.table_tunemat.verticalHeader().setStyleSheet(""" min-width:1.55em; max-width:1.55em;""") self.table_tunemat.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_tunemat.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_tunemat.setSizePolicy(QSzPlcy.MinimumExpanding, QSzPlcy.Preferred) label_nomKL = QLabel('<h4>Nominal KL</h4>') label_nomKL.setAlignment(Qt.AlignCenter) self.table_nomKL = QTableWidget(self) self.table_nomKL.setObjectName('nomKL') self.table_nomKL.setStyleSheet(""" #nomKL{ background-color: #efebe7; min-width: 22.14em; min-height: 4em; max-height: 4em;}""") self.table_nomKL.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table_nomKL.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_nomKL.setRowCount(1) self.table_nomKL.setColumnCount(2) self.table_nomKL.setVerticalHeaderLabels(['KL']) self.table_nomKL.setHorizontalHeaderLabels(['QF', 'QD']) self.table_nomKL.horizontalHeader().setStyleSheet(""" min-height:1.55em; max-height:1.55em;""") self.table_nomKL.verticalHeader().setStyleSheet(""" min-width:1.55em; max-width:1.55em;""") self.table_nomKL.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_nomKL.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_nomKL.setSizePolicy(QSzPlcy.MinimumExpanding, QSzPlcy.Preferred) lay = QVBoxLayout() lay.addWidget(l_tuneconfig) lay.addWidget(self.le_tuneconfig) lay.addItem(QSpacerItem(20, 10, QSzPlcy.Ignored, QSzPlcy.Expanding)) lay.addWidget(label_tunemat) lay.addWidget(self.table_tunemat) lay.addItem(QSpacerItem(20, 10, QSzPlcy.Ignored, QSzPlcy.Expanding)) lay.addWidget(label_nomKL) lay.addWidget(self.table_nomKL) lay.addItem(QSpacerItem(20, 10, QSzPlcy.Ignored, QSzPlcy.Expanding)) return lay def _setupChromSettings(self): l_chromconfig = QLabel('<h3>Chromaticity Variation Config</h3>', self) l_chromconfig.setAlignment(Qt.AlignCenter) self.le_chromconfig = _ConfigLineEdit( parent=self, config_type='bo_chromcorr_params') self.le_chromconfig.textChanged.connect(self._showChromConfigData) l_chrommat = QLabel('<h4>Matrix</h4>', self) l_chrommat.setAlignment(Qt.AlignCenter) self.table_chrommat = QTableWidget(self) self.table_chrommat.setObjectName('chrommat') self.table_chrommat.setStyleSheet(""" #chrommat{ background-color: #efebe7; min-width: 22.14em; min-height: 6em; max-height: 6em;}""") self.table_chrommat.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table_chrommat.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_chrommat.setRowCount(2) self.table_chrommat.setColumnCount(2) self.table_chrommat.setVerticalHeaderLabels([' X', ' Y']) self.table_chrommat.setHorizontalHeaderLabels(['SF', 'SD']) self.table_chrommat.horizontalHeader().setStyleSheet(""" min-height:1.55em; max-height:1.55em;""") self.table_chrommat.verticalHeader().setStyleSheet(""" min-width:1.55em; max-width:1.55em;""") self.table_chrommat.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_chrommat.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_chrommat.setSizePolicy(QSzPlcy.MinimumExpanding, QSzPlcy.Preferred) l_nomSL = QLabel('<h4>Nominal SL</h4>') l_nomSL.setAlignment(Qt.AlignCenter) self.table_nomSL = QTableWidget(self) self.table_nomSL.setObjectName('nomSL') self.table_nomSL.setStyleSheet(""" #nomSL{ background-color: #efebe7; min-width: 22.14em; min-height: 4em; max-height: 4em;}""") self.table_nomSL.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.table_nomSL.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table_nomSL.setRowCount(1) self.table_nomSL.setColumnCount(2) self.table_nomSL.setVerticalHeaderLabels(['SL']) self.table_nomSL.setHorizontalHeaderLabels(['SF', 'SD']) self.table_nomSL.horizontalHeader().setStyleSheet(""" min-height:1.55em; max-height:1.55em;""") self.table_nomSL.verticalHeader().setStyleSheet(""" min-width:1.55em; max-width:1.55em;""") self.table_nomSL.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_nomSL.verticalHeader().setSectionResizeMode( QHeaderView.Stretch) self.table_nomSL.setSizePolicy(QSzPlcy.MinimumExpanding, QSzPlcy.Preferred) l_nomchrom = QLabel('<h4>Nominal Chrom</h4>') l_nomchrom.setAlignment(Qt.AlignCenter) self.label_nomchrom = QLabel() self.label_nomchrom.setAlignment(Qt.AlignCenter) lay = QVBoxLayout() lay.addWidget(l_chromconfig) lay.addWidget(self.le_chromconfig) lay.addItem(QSpacerItem(20, 10, QSzPlcy.Expanding, QSzPlcy.Expanding)) lay.addWidget(l_chrommat) lay.addWidget(self.table_chrommat) lay.addItem(QSpacerItem(20, 10, QSzPlcy.Expanding, QSzPlcy.Expanding)) lay.addWidget(l_nomSL) lay.addWidget(self.table_nomSL) lay.addItem(QSpacerItem(20, 10, QSzPlcy.Expanding, QSzPlcy.Expanding)) lay.addWidget(l_nomchrom) lay.addWidget(self.label_nomchrom) return lay def _showTuneConfigData(self): try: name = self.le_tuneconfig.text() config = self.conn_tuneparams.get_config_value(name=name) mat = config['matrix'] nomKL = config['nominal KLs'] except _ConfigDBException as err: QMessageBox.critical(self, 'Error', str(err), QMessageBox.Ok) else: self.tuneconfig_currname = name self.table_tunemat.setItem(0, 0, QTableWidgetItem(str(mat[0][0]))) self.table_tunemat.setItem(0, 1, QTableWidgetItem(str(mat[0][1]))) self.table_tunemat.setItem(1, 0, QTableWidgetItem(str(mat[1][0]))) self.table_tunemat.setItem(1, 1, QTableWidgetItem(str(mat[1][1]))) self.table_tunemat.item(0, 0).setFlags(Qt.ItemIsEnabled) self.table_tunemat.item(0, 1).setFlags(Qt.ItemIsEnabled) self.table_tunemat.item(1, 0).setFlags(Qt.ItemIsEnabled) self.table_tunemat.item(1, 1).setFlags(Qt.ItemIsEnabled) self.table_nomKL.setItem(0, 0, QTableWidgetItem(str(nomKL[0]))) self.table_nomKL.setItem(0, 1, QTableWidgetItem(str(nomKL[1]))) self.table_nomKL.item(0, 0).setFlags(Qt.ItemIsEnabled) self.table_nomKL.item(0, 1).setFlags(Qt.ItemIsEnabled) def _showChromConfigData(self): try: name = self.le_chromconfig.text() config = self.conn_chromparams.get_config_value(name=name) mat = config['matrix'] nomSL = config['nominal SLs'] nomChrom = config['nominal chrom'] except _ConfigDBException as err: QMessageBox.critical(self, 'Error', str(err), QMessageBox.Ok) else: self.chromconfig_currname = name self.table_chrommat.setItem(0, 0, QTableWidgetItem(str(mat[0][0]))) self.table_chrommat.setItem(0, 1, QTableWidgetItem(str(mat[0][1]))) self.table_chrommat.setItem(1, 0, QTableWidgetItem(str(mat[1][0]))) self.table_chrommat.setItem(1, 1, QTableWidgetItem(str(mat[1][1]))) self.table_chrommat.item(0, 0).setFlags(Qt.ItemIsEnabled) self.table_chrommat.item(0, 1).setFlags(Qt.ItemIsEnabled) self.table_chrommat.item(1, 0).setFlags(Qt.ItemIsEnabled) self.table_chrommat.item(1, 1).setFlags(Qt.ItemIsEnabled) self.table_nomSL.setItem(0, 0, QTableWidgetItem(str(nomSL[0]))) self.table_nomSL.setItem(0, 1, QTableWidgetItem(str(nomSL[1]))) self.table_nomSL.item(0, 0).setFlags(Qt.ItemIsEnabled) self.table_nomSL.item(0, 1).setFlags(Qt.ItemIsEnabled) self.label_nomchrom.setText(str(nomChrom)) def _emitSettings(self): tuneconfig_name = self.le_tuneconfig.text() chromconfig_name = self.le_chromconfig.text() self.updateSettings.emit(tuneconfig_name, chromconfig_name) self.close()