class ImportDialog(QDialog): def __init__(self, import_dict, local_dict, viewer, parent=None): """ :type import_dict: dict[str, object] :type local_dict: dict[str, object] :param import_dict: :param local_dict: :param viewer: """ super().__init__(parent=parent) self.setWindowTitle("Import") self.viewer = viewer() self.local_viewer = viewer() self.import_dict = import_dict self.local_dict = local_dict conflicts = set(local_dict.keys()) & set(import_dict.keys()) # print(conflicts) self.list_view = QTreeWidget() self.list_view.setColumnCount(4) self.radio_group_list = [] self.checked_num = len(import_dict) def rename_func(ob_name, new_name_field, rename_radio): end_reg = re.compile(r"(.*) \((\d+)\)$") def in_func(): if not rename_radio.isChecked() or str(new_name_field.text()).strip() != "": return match = end_reg.match(ob_name) if match: new_name_format = match.group(1) + " ({})" i = int(match.group(2)) + 1 else: new_name_format = ob_name + " ({})" i = 1 while new_name_format.format(i) in self.local_dict: i += 1 new_name_field.setText(new_name_format.format(i)) return in_func def block_import(radio_btn, name_field): def inner_func(): text = str(name_field.text()).strip() if text == "" and radio_btn.isChecked(): self.import_btn.setDisabled(True) else: self.import_btn.setEnabled(True) return inner_func for name in sorted(import_dict.keys()): item = QTreeWidgetItem() item.setText(0, name) # noinspection PyTypeChecker item.setFlags(item.flags() | Qt.ItemIsUserCheckable) item.setCheckState(0, Qt.Checked) self.list_view.addTopLevelItem(item) if name in conflicts: group = QButtonGroup() overwrite = QRadioButton("Overwrite") overwrite.setChecked(True) rename = QRadioButton("Rename") new_name = QLineEdit() new_name.textChanged.connect(block_import(rename, new_name)) rename.toggled.connect(block_import(rename, new_name)) overwrite.toggled.connect(block_import(rename, new_name)) rename.toggled.connect(rename_func(name, new_name, rename)) group.addButton(overwrite) group.addButton(rename) self.radio_group_list.append(group) self.list_view.setItemWidget(item, 1, overwrite) self.list_view.setItemWidget(item, 2, rename) self.list_view.setItemWidget(item, 3, new_name) self.import_btn = QPushButton("Import") self.cancel_btn = QPushButton("Cancel") self.check_btn = QPushButton("Check all") self.uncheck_btn = QPushButton("Uncheck all") self.cancel_btn.clicked.connect(self.close) self.import_btn.clicked.connect(self.accept) self.check_btn.clicked.connect(self.check_all) self.uncheck_btn.clicked.connect(self.uncheck_all) self.list_view.itemSelectionChanged.connect(self.preview) self.list_view.itemChanged.connect(self.checked_change) layout = QVBoxLayout() info_layout = QHBoxLayout() info_layout.addWidget(self.list_view, 2) v1_lay = QVBoxLayout() v1_lay.addWidget(QLabel("Import:")) v1_lay.addWidget(self.viewer) info_layout.addLayout(v1_lay, 1) # info_layout.addWidget(self.local_viewer, 1) v2_lay = QVBoxLayout() v2_lay.addWidget(QLabel("Local:")) v2_lay.addWidget(self.local_viewer) info_layout.addLayout(v2_lay, 1) layout.addLayout(info_layout) btn_layout = QHBoxLayout() btn_layout.addWidget(self.check_btn) btn_layout.addWidget(self.uncheck_btn) btn_layout.addStretch() btn_layout.addWidget(self.import_btn) btn_layout.addWidget(self.cancel_btn) layout.addLayout(btn_layout) self.setLayout(layout) def preview(self): item = self.list_view.currentItem() name = str(item.text(0)) self.viewer.preview_object(self.import_dict[name]) if self.list_view.itemWidget(item, 1) is not None: self.local_viewer.preview_object(self.local_dict[name]) else: self.local_viewer.clear() def checked_change(self, item, _): if item.checkState(0) == Qt.Unchecked: self.checked_num -= 1 if self.list_view.itemWidget(item, 1) is not None: self.list_view.itemWidget(item, 1).setDisabled(True) self.list_view.itemWidget(item, 2).setDisabled(True) self.list_view.itemWidget(item, 3).setDisabled(True) else: self.checked_num += 1 if self.list_view.itemWidget(item, 1) is not None: self.list_view.itemWidget(item, 1).setEnabled(True) self.list_view.itemWidget(item, 2).setEnabled(True) self.list_view.itemWidget(item, 3).setEnabled(True) if self.checked_num == 0: self.import_btn.setDisabled(True) else: self.import_btn.setEnabled(True) def get_import_list(self): res = [] for index in range(self.list_view.topLevelItemCount()): item = self.list_view.topLevelItem(index) if item.checkState(0) == Qt.Checked: chk = self.list_view.itemWidget(item, 2) if chk is not None and chk.isChecked(): res.append((str(item.text(0)), str(self.list_view.itemWidget(item, 3).text()))) else: name = str(item.text(0)) res.append((name, name)) return res def uncheck_all(self): for index in range(self.list_view.topLevelItemCount()): item = self.list_view.topLevelItem(index) item.setCheckState(0, Qt.Unchecked) self.check_state[...] = False self.import_btn.setDisabled(True) self.checked_num = 0 def check_all(self): for index in range(self.list_view.topLevelItemCount()): item = self.list_view.topLevelItem(index) item.setCheckState(0, Qt.Checked) self.checked_num = len(self.import_dict) self.check_state[...] = True self.import_btn.setDisabled(False)
class MetaboliteList(QWidget): """A list of metabolites""" def __init__(self, appdata: CnaData): QWidget.__init__(self) self.appdata = appdata self.last_selected = None self.metabolite_list = QTreeWidget() self.metabolite_list.setHeaderLabels(["Id", "Name"]) self.metabolite_list.setSortingEnabled(True) for m in self.appdata.project.cobra_py_model.metabolites: self.add_metabolite(m) self.metabolite_list.setContextMenuPolicy(Qt.CustomContextMenu) self.metabolite_list.customContextMenuRequested.connect( self.on_context_menu) # create context menu self.pop_menu = QMenu(self.metabolite_list) in_out_fluxes_action = QAction( 'compute in/out fluxes for this metabolite', self.metabolite_list) self.pop_menu.addAction(in_out_fluxes_action) in_out_fluxes_action.triggered.connect(self.emit_in_out_fluxes_action) self.metabolite_mask = MetabolitesMask(appdata) self.metabolite_mask.hide() self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.splitter = QSplitter() self.splitter.setOrientation(Qt.Vertical) self.splitter.addWidget(self.metabolite_list) self.splitter.addWidget(self.metabolite_mask) self.layout.addWidget(self.splitter) self.setLayout(self.layout) self.metabolite_list.currentItemChanged.connect( self.metabolite_selected) self.metabolite_mask.metaboliteChanged.connect( self.handle_changed_metabolite) self.metabolite_mask.jumpToReaction.connect( self.emit_jump_to_reaction) def clear(self): self.metabolite_list.clear() self.metabolite_mask.hide() def add_metabolite(self, metabolite): item = QTreeWidgetItem(self.metabolite_list) item.setText(0, metabolite.id) item.setText(1, metabolite.name) item.setData(2, 0, metabolite) def on_context_menu(self, point): if len(self.appdata.project.cobra_py_model.metabolites) > 0: self.pop_menu.exec_(self.mapToGlobal(point)) def update_annotations(self, annotation): self.metabolite_mask.annotation.itemChanged.disconnect( self.metabolite_mask.throttler.throttle) c = self.metabolite_mask.annotation.rowCount() for i in range(0, c): self.metabolite_mask.annotation.removeRow(0) i = 0 for key in annotation: self.metabolite_mask.annotation.insertRow(i) keyl = QTableWidgetItem(key) iteml = QTableWidgetItem(str(annotation[key])) self.metabolite_mask.annotation.setItem(i, 0, keyl) self.metabolite_mask.annotation.setItem(i, 1, iteml) i += 1 self.metabolite_mask.annotation.itemChanged.connect( self.metabolite_mask.throttler.throttle) def handle_changed_metabolite(self, metabolite: cobra.Metabolite): # Update metabolite item in list root = self.metabolite_list.invisibleRootItem() child_count = root.childCount() for i in range(child_count): item = root.child(i) if item.data(2, 0) == metabolite: old_id = item.text(0) item.setText(0, metabolite.id) item.setText(1, metabolite.name) break self.last_selected = self.metabolite_mask.id.text() self.metaboliteChanged.emit(old_id, metabolite) def update_selected(self, string): root = self.metabolite_list.invisibleRootItem() child_count = root.childCount() for i in range(child_count): item = root.child(i) item.setHidden(True) for item in self.metabolite_list.findItems(string, Qt.MatchContains, 0): item.setHidden(False) for item in self.metabolite_list.findItems(string, Qt.MatchContains, 1): item.setHidden(False) def metabolite_selected(self, item, _column): if item is None: self.metabolite_mask.hide() else: self.metabolite_mask.show() metabolite: cobra.Metabolite = item.data(2, 0) self.metabolite_mask.metabolite = metabolite self.metabolite_mask.id.setText(metabolite.id) self.metabolite_mask.name.setText(metabolite.name) self.metabolite_mask.formula.setText(metabolite.formula) if metabolite.charge is None: pass else: self.metabolite_mask.charge.setText(str(metabolite.charge)) self.metabolite_mask.compartment.setText(metabolite.compartment) self.update_annotations(metabolite.annotation) self.metabolite_mask.changed = False turn_white(self.metabolite_mask.id) turn_white(self.metabolite_mask.name) turn_white(self.metabolite_mask.formula) turn_white(self.metabolite_mask.charge) turn_white(self.metabolite_mask.compartment) self.metabolite_mask.is_valid = True self.metabolite_mask.update_state() def update(self): self.metabolite_list.clear() for m in self.appdata.project.cobra_py_model.metabolites: self.add_metabolite(m) if self.last_selected is None: pass else: items = self.metabolite_list.findItems( self.last_selected, Qt.MatchExactly) for i in items: self.metabolite_list.setCurrentItem(i) break def set_current_item(self, key): self.last_selected = key self.update() def emit_jump_to_reaction(self, reaction): self.jumpToReaction.emit(reaction) def emit_in_out_fluxes_action(self): self.computeInOutFlux.emit(self.metabolite_list.currentItem().text(0)) itemActivated = Signal(str) metaboliteChanged = Signal(str, cobra.Metabolite) jumpToReaction = Signal(str) computeInOutFlux = Signal(str)