def __init__(self, value, parent=None): QLineEdit.__init__(self, str(value), parent) self.setAlignment(Qt.AlignRight) if isinstance(value, int): self.setValidator(QIntValidator()) elif isinstance(value, float): self.setValidator(QDoubleValidator())
class LigandTable(QWidget): def __init__( self, parent=None, singleSelect=False, maxDenticity=None, include_substituents=False, ): super().__init__(parent) self._include_substituents = include_substituents layout = QGridLayout(self) self.table = QTableWidget() self.table.setColumnCount(3) self.table.setHorizontalHeaderLabels( ['name', 'denticity', 'coordinating elements']) self.add_ligands(maxDenticity) for i in range(0, 3): self.table.resizeColumnToContents(i) self.table.horizontalHeader().setStretchLastSection(False) self.table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Stretch) self.table.setSortingEnabled(True) self.table.setSelectionBehavior(QTableWidget.SelectRows) if singleSelect: self.table.setSelectionMode(QTableWidget.SingleSelection) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.filterEdit = QLineEdit() self.filterEdit.textChanged.connect(self.apply_filter) self.filterEdit.setClearButtonEnabled(True) self.filter_columns = QComboBox() self.filter_columns.addItem("name") self.filter_columns.addItem("denticity") self.filter_columns.addItem("coordinating elements") self.filter_columns.currentTextChanged.connect( self.change_filter_method) self.name_regex_option = QComboBox() self.name_regex_option.addItem("case-insensitive") self.name_regex_option.addItem("case-sensitive") self.name_regex_option.currentTextChanged.connect(self.apply_filter) self.name_regex_option.setVisible( self.filter_columns.currentText() == "name") self.coordinating_elements_method = QComboBox() self.coordinating_elements_method.addItem("exactly") self.coordinating_elements_method.addItem("at least") self.coordinating_elements_method.currentTextChanged.connect( self.apply_filter) self.coordinating_elements_method.setVisible( self.filter_columns.currentText() == "coordinating elements") layout.addWidget(self.table, 0, 0, 1, 4) layout.addWidget(QLabel("filter based on"), 1, 0) layout.addWidget(self.filter_columns, 1, 1) layout.addWidget(self.coordinating_elements_method, 1, 2) layout.addWidget(self.name_regex_option, 1, 2) layout.addWidget(self.filterEdit, 1, 3) self.change_filter_method("name") def add_ligands(self, maxDenticity=None): from AaronTools.component import Component names = [] for lib in [Component.AARON_LIBS, Component.BUILTIN]: if not os.path.exists(lib): continue for lig in os.listdir(lib): name, ext = os.path.splitext(lig) if not any(".%s" % x == ext for x in read_types): continue if name in names: continue names.append(name) geom = Geometry( os.path.join(lib, lig), refresh_connected=False, refresh_ranks=False, ) key_atoms = [geom.atoms[i] for i in geom.other["key_atoms"]] if maxDenticity and len(key_atoms) > maxDenticity: continue row = self.table.rowCount() self.table.insertRow(row) self.table.setItem(row, 0, QTableWidgetItem(name)) #this is an integer, so I need to initialize it then set the data denticity = QTableWidgetItem() denticity.setData(Qt.DisplayRole, len(key_atoms)) self.table.setItem(row, 1, denticity) self.table.setItem( row, 2, QTableWidgetItem(", ".join( sorted([atom.element for atom in key_atoms])))) if self._include_substituents: from AaronTools.substituent import Substituent for lib in [Substituent.AARON_LIBS, Substituent.BUILTIN]: if not os.path.exists(lib): continue for sub in os.listdir(lib): name, ext = os.path.splitext(sub) if not any(".%s" % x == ext for x in read_types): continue if name in names: continue names.append(name) geom = Geometry( os.path.join(lib, sub), refresh_connected=False, refresh_ranks=False, ) key_atoms = [geom.atoms[0]] if maxDenticity and len(key_atoms) > maxDenticity: continue row = self.table.rowCount() self.table.insertRow(row) self.table.setItem(row, 0, QTableWidgetItem(name)) #this is an integer, so I need to initialize it then set the data denticity = QTableWidgetItem() denticity.setData(Qt.DisplayRole, len(key_atoms)) self.table.setItem(row, 1, denticity) self.table.setItem( row, 2, QTableWidgetItem(", ".join( sorted([atom.element for atom in key_atoms])))) self.ligand_list = names def change_filter_method(self, text): if text == "coordinating elements": self.filterEdit.setToolTip("comma and/or space delimited elements") self.coordinating_elements_method.setVisible(True) self.name_regex_option.setVisible(False) elif text == "name": self.filterEdit.setToolTip("name regex") self.coordinating_elements_method.setVisible(False) self.name_regex_option.setVisible(True) elif text == "denticity": self.filterEdit.setToolTip("number of key atoms") self.coordinating_elements_method.setVisible(False) self.name_regex_option.setVisible(False) self.apply_filter() def apply_filter(self, *args): text = self.filterEdit.text() if text: if self.filter_columns.currentText() == "name": m = QRegularExpression(text) if m.isValid(): if self.name_regex_option.currentText( ) == "case-insensitive": m.setPatternOptions( QRegularExpression.CaseInsensitiveOption) m.optimize() filter = lambda row_num: m.match( self.table.item(row_num, 0).text()).hasMatch() else: return elif self.filter_columns.currentText() == "denticity": if text.isdigit(): filter = lambda row_num: int( self.table.item(row_num, 1).text()) == int(text) else: filter = lambda row: True elif self.filter_columns.currentText() == "coordinating elements": method = self.coordinating_elements_method.currentText() def filter(row_num): row_key_atoms = [ item.strip() for item in self.table.item( row_num, 2).text().split(',') ] search_atoms = [] for item in text.split(): for ele in item.split(','): if ele.strip() != "": search_atoms.append(ele) if method == "exactly": if all([row_key_atoms.count(element) == search_atoms.count(element) for element in set(search_atoms)]) and \ all([row_key_atoms.count(element) == search_atoms.count(element) for element in set(row_key_atoms)]): return True else: return False elif method == "at least": if all([ row_key_atoms.count(element) >= search_atoms.count(element) for element in set(search_atoms) ]): return True else: return False else: filter = lambda row: True for i in range(0, self.table.rowCount()): self.table.setRowHidden(i, not filter(i))
class BaseFileFolderDialog(BaseDialog, abstract_dialog.AbstractFileFolderDialog): """ Base dialog classes for folders and files """ def_title = 'Select File' def_size = (200, 125) def_use_app_browser = False def __init__(self, name='BaseFileFolder', parent=None, **kwargs): super(BaseFileFolderDialog, self).__init__(name=name, parent=parent) self.directory = None self.filters = None self._use_app_browser = kwargs.pop('use_app_browser', self.def_use_app_browser) self.set_filters('All Files (*.*)') # By default, we set the directory to the user folder self.set_directory(os.path.expanduser('~')) self.center() def open_app_browser(self): return def ui(self): super(BaseFileFolderDialog, self).ui() from tpDcc.libs.qt.widgets import directory self.places = dict() self.grid = layouts.GridLayout() sub_grid = layouts.GridLayout() self.grid.addWidget(QLabel('Path:'), 0, 0, Qt.AlignRight) self.path_edit = QLineEdit(self) self.path_edit.setReadOnly(True) self.filter_box = QComboBox(self) self.file_edit = QLineEdit(self) self.view = directory.FileListWidget(self) self.view.setWrapping(True) self.view.setFocusPolicy(Qt.StrongFocus) self.open_button = QPushButton('Select', self) self.cancel_button = QPushButton('Cancel', self) size = QSize(32, 24) self.up_button = QPushButton('Up') self.up_button.setToolTip('Go up') self.up_button.setMinimumSize(size) self.up_button.setMaximumSize(size) size = QSize(56, 24) self.refresh_button = QPushButton('Reload') self.refresh_button.setToolTip('Reload file list') self.refresh_button.setMinimumSize(size) self.refresh_button.setMaximumSize(size) self.show_hidden = QCheckBox('Hidden') self.show_hidden.setChecked(False) self.show_hidden.setToolTip('Toggle show hidden files') sub_grid.addWidget(self.up_button, 0, 1) sub_grid.addWidget(self.path_edit, 0, 2) sub_grid.addWidget(self.refresh_button, 0, 3) sub_grid.addWidget(self.show_hidden, 0, 4) self.grid.addLayout(sub_grid, 0, 1) self.grid.addWidget(self.get_drives_widget(), 1, 0) self.grid.addWidget(self.view, 1, 1) self.grid.addWidget(QLabel('File name:'), 7, 0, Qt.AlignRight) self.grid.addWidget(self.file_edit, 7, 1) self.filter_label = QLabel('Filter:') self.grid.addWidget(self.filter_label, 8, 0, Qt.AlignRight) self.grid.addWidget(self.filter_box, 8, 1) hbox = layouts.GridLayout() hbox.addWidget(self.open_button, 0, 0, Qt.AlignRight) hbox.addWidget(self.cancel_button, 0, 1, Qt.AlignRight) self.grid.addLayout(hbox, 9, 1, Qt.AlignRight) self.main_layout.addLayout(self.grid) self.setGeometry(200, 100, 600, 400) self.open_button.clicked.connect(self.accept) self.cancel_button.clicked.connect(self.reject) self.up_button.clicked.connect(self.go_up) self.refresh_button.clicked.connect(self.update_view) self.show_hidden.stateChanged.connect(self.update_view) self.view.directory_activated.connect( self.activate_directory_from_view) self.view.file_activated.connect(self.activate_file_from_view) self.view.file_selected.connect(self.select_file_item) self.view.folder_selected.connect(self.select_folder_item) self.view.up_requested.connect(self.go_up) self.view.update_requested.connect(self.update_view) def exec_(self, *args, **kwargs): if self._use_app_browser: return self.open_app_browser() else: self.update_view() self.filter_box.currentIndexChanged.connect(self.update_view) accepted = super(BaseFileFolderDialog, self).exec_() self.filter_box.currentIndexChanged.disconnect(self.update_view) return self.get_result() if accepted == 1 else None def set_filters(self, filters, selected=0): self.filter_box.clear() filter_types = filters.split(';;') for ft in filter_types: extensions = string.extract(ft, '(', ')') filter_name = string.rstrips(ft, '({})'.format(extensions)) extensions = extensions.split(' ') self.filter_box.addItem( '{} ({})'.format(filter_name, ','.join(extensions)), extensions) if 0 <= selected < self.filter_box.count(): self.filter_box.setCurrentIndex(selected) self.filters = filters def get_drives_widget(self): """ Returns a QGroupBox widget that contains all disk drivers of the PC in a vertical layout :return: QGroupBox """ w = QGroupBox('') w.setParent(self) box = layouts.VerticalLayout() box.setAlignment(Qt.AlignTop) places = [(getpass.getuser(), os.path.realpath(os.path.expanduser('~')))] places += [ (q, q) for q in [os.path.realpath(x.absolutePath()) for x in QDir().drives()] ] for label, loc in places: icon = QFileIconProvider().icon(QFileInfo(loc)) drive_btn = QRadioButton(label) drive_btn.setIcon(icon) drive_btn.setToolTip(loc) drive_btn.setProperty('path', loc) drive_btn.clicked.connect(self.go_to_drive) self.places[loc] = drive_btn box.addWidget(drive_btn) w.setLayout(box) return w def go_to_drive(self): """ Updates widget to show the content of the selected disk drive """ sender = self.sender() self.set_directory(sender.property('path'), False) def get_result(self): tf = self.file_edit.text() sf = self.get_file_path(tf) return sf, os.path.dirname(sf), tf.split(os.pathsep) def get_filter_patterns(self): """ Get list of filter patterns that are being used by the widget :return: list<str> """ idx = self.filter_box.currentIndex() if idx >= 0: return self.filter_box.itemData(idx) else: return [] def get_file_path(self, file_name): """ Returns file path of the given file name taking account the selected directory :param file_name: str, name of the file without path :return: str """ sname = file_name.split(os.pathsep)[0] return os.path.realpath( os.path.join(os.path.abspath(self.directory), sname)) # def accept(self): # self._overlay.close() # super(BaseFileFolderDialog, self).accept() # # # def reject(self): # self._overlay.close() # super(BaseFileFolderDialog, self).reject() def update_view(self): """ Updates file/folder view :return: """ self.view.clear() qdir = QDir(self.directory) qdir.setNameFilters(self.get_filter_patterns()) filters = QDir.Dirs | QDir.AllDirs | QDir.Files | QDir.NoDot | QDir.NoDotDot if self.show_hidden.isChecked(): filters = filters | QDir.Hidden entries = qdir.entryInfoList(filters=filters, sort=QDir.DirsFirst | QDir.Name) file_path = self.get_file_path('..') if os.path.exists(file_path) and file_path != self.directory: icon = QFileIconProvider().icon(QFileInfo(self.directory)) QListWidgetItem(icon, '..', self.view, 0) for info in entries: icon = QFileIconProvider().icon(info) suf = info.completeSuffix() name, tp = (info.fileName(), 0) if info.isDir() else ( '%s%s' % (info.baseName(), '.%s' % suf if suf else ''), 1) QListWidgetItem(icon, name, self.view, tp) self.view.setFocus() def set_directory(self, path, check_drive=True): """ Sets the directory that you want to explore :param path: str, valid path :param check_drive: bool, :return: """ self.directory = os.path.realpath(path) self.path_edit.setText(self.directory) self.file_edit.setText('') # If necessary, update selected disk driver if check_drive: for loc in self.places: rb = self.places[loc] rb.setAutoExclusive(False) rb.setChecked(loc.lower() == self.directory.lower()) rb.setAutoExclusive(True) self.update_view() self.up_button.setEnabled(not self.cant_go_up()) def go_up(self): """ Updates the current directory to go to its parent directory """ self.set_directory(os.path.dirname(self.directory)) def cant_go_up(self): """ Checks whether we can naviage to current selected parent directory or not :return: bool """ return os.path.dirname(self.directory) == self.directory def activate_directory_from_view(self, name): """ Updates selected directory :param name: str, name of the directory """ self.set_directory(os.path.join(self.directory, name)) def activate_file_from_view(self, name): """ Updates selected file text and returns its info by accepting it :param name: str, name of the file """ self.select_file_item(name=name) self.accept() def select_file_item(self, name): """ Updates selected file text and returns its info by accepting it :param name: str, name of the file """ self.file_edit.setText(name) def select_folder_item(self, name): """ Updates selected folder text and returns its info by accepting it :param name: str, name of the folder """ self.file_edit.setText(name)
def onUpdatePropertyView(self, formLayout): # name le_name = QLineEdit(self.getName()) le_name.setReadOnly(True) if self.label().IsRenamable(): le_name.setReadOnly(False) le_name.returnPressed.connect(lambda: self.setName(le_name.text())) formLayout.addRow("Name", le_name) # uid leUid = QLineEdit(str(self.uid)) leUid.setReadOnly(True) formLayout.addRow("Uuid", leUid) # type leType = QLineEdit(self.__class__.__name__) leType.setReadOnly(True) formLayout.addRow("Type", leType) # pos le_pos = QLineEdit("{0} x {1}".format(self.pos().x(), self.pos().y())) formLayout.addRow("Pos", le_pos) # inputs if len([i for i in self.inputs.values()]) != 0: sep_inputs = QLabel() sep_inputs.setStyleSheet("background-color: black;") sep_inputs.setText("INPUTS") formLayout.addRow("", sep_inputs) for inp in self.inputs.values(): dataSetter = inp.call if inp.dataType == DataTypes.Exec else inp.setData w = getInputWidget(inp.dataType, dataSetter, inp.defaultValue(), inp.getUserStruct()) if w: w.setWidgetValue(inp.currentData()) w.setObjectName(inp.getName()) formLayout.addRow(inp.name, w) if inp.hasConnections(): w.setEnabled(False) # outputs if len([i for i in self.outputs.values()]) != 0: sep_outputs = QLabel() sep_outputs.setStyleSheet("background-color: black;") sep_outputs.setText("OUTPUTS") formLayout.addRow("", sep_outputs) for out in self.outputs.values(): if out.dataType == DataTypes.Exec: continue w = getInputWidget(out.dataType, out.setData, out.defaultValue(), out.getUserStruct()) if w: w.setWidgetValue(out.currentData()) w.setObjectName(out.getName()) formLayout.addRow(out.name, w) if out.hasConnections(): w.setEnabled(False) doc_lb = QLabel() doc_lb.setStyleSheet("background-color: black;") doc_lb.setText("Description") formLayout.addRow("", doc_lb) doc = QTextBrowser() doc.setOpenExternalLinks(True) doc.setHtml(self.description()) formLayout.addRow("", doc)
def addAttributeSlot(self): """ Adds a new attribute (column) to the table """ dialog = QDialog(self) dialog.setModal(True) dialog.setWindowTitle('Add Attribute') layout = QVBoxLayout() dialog.setLayout(layout) form = QFormLayout() nameBox = QLineEdit() typeCombo = QComboBox() for attrType in _attrTypes: typeName = partio.TypeName(attrType) typeCombo.addItem(typeName) typeCombo.setCurrentIndex(partio.FLOAT) countBox = QLineEdit() countBox.setValidator(QIntValidator()) countBox.setText('1') fixedCheckbox = QCheckBox() valueBox = QLineEdit() valueBox.setText('0') form.addRow('Name:', nameBox) form.addRow('Type:', typeCombo) form.addRow('Count:', countBox) form.addRow('Fixed:', fixedCheckbox) form.addRow('Default Value:', valueBox) layout.addLayout(form) buttons = QHBoxLayout() layout.addLayout(buttons) add = QPushButton('Add') add.clicked.connect(dialog.accept) buttons.addWidget(add) cancel = QPushButton('Cancel') cancel.clicked.connect(dialog.reject) buttons.addWidget(cancel) if not dialog.exec_(): return name = str(nameBox.text()) if not name: print('Please supply a name for the new attribute') # TODO: prompt return attrType = typeCombo.currentIndex() count = int(countBox.text()) fixed = fixedCheckbox.isChecked() values = list(str(valueBox.text()).strip().split()) for i in range(count): if i < len(values): value = values[i] else: value = values[-1] if attrType == partio.INT or attrType == partio.INDEXEDSTR: values[i] = int(value) elif attrType == partio.FLOAT or attrType == partio.VECTOR: values[i] = float(value) # pylint:disable=R0204 else: values[i] = 0.0 # pylint:disable=R0204 value = tuple(values) self.data.addAttribute(name, attrType, count, fixed, value)
class TestRunner(ToolInstance): def __init__(self, session, name): super().__init__(session, name) self.tool_window = MainToolWindow(self) self._build_ui() def _build_ui(self): """ ui should have: * table with a list of available tests and show results after they are done * way to filter tests * button to run tests """ layout = QFormLayout() # table to list test classes and the results self.table = QTableWidget() self.table.setColumnCount(2) self.table.setHorizontalHeaderLabels(["test", "result"]) self.table.horizontalHeader().setSectionResizeMode( 0, self.table.horizontalHeader().Interactive) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.table.horizontalHeader().setSectionResizeMode( 1, self.table.horizontalHeader().Stretch) self.table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.table.setSelectionBehavior(self.table.SelectRows) layout.addRow(self.table) self.filter = QLineEdit() self.filter.setPlaceholderText("filter test names") self.filter.setClearButtonEnabled(True) self.filter.textChanged.connect(self.apply_filter) layout.addRow(self.filter) self.profile = QCheckBox() self.profile.setToolTip("profile functions called during testing " "using cProfile") layout.addRow("profile calls:", self.profile) self.run_button = QPushButton("run tests") self.run_button.clicked.connect(self.run_tests) self.run_button.setToolTip( "if no tests are selected on the table, run all tests\n" + "otherwise, run selected tests") layout.addRow(self.run_button) self.fill_table() self.table.resizeColumnToContents(0) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None) def apply_filter(self, text=None): """filter table to only show tests matching text""" if text is None: text = self.filter.text() if text: text = text.replace("(", "\(") text = text.replace(")", "\)") m = QRegularExpression(text) m.setPatternOptions(QRegularExpression.CaseInsensitiveOption) if m.isValid(): m.optimize() filter = lambda row_num: m.match( self.table.item(row_num, 0).text()).hasMatch() else: return else: filter = lambda row: True for i in range(0, self.table.rowCount()): self.table.setRowHidden(i, not filter(i)) def fill_table(self): """adds test names to the table""" mgr = self.session.test_manager for name in mgr.tests.keys(): row = self.table.rowCount() self.table.insertRow(row) test_name = QTableWidgetItem() test_name.setData(Qt.DisplayRole, name) self.table.setItem(row, 0, test_name) def run_tests(self): """run the tests selected on the table and show the results""" from TestManager.commands.test import test test_list = [] use_selected = True for row in self.table.selectionModel().selectedRows(): if self.table.isRowHidden(row.row()): continue test_name = self.table.item(row.row(), 0).text() test_list.append(test_name) if not test_list: use_selected = False for i in range(0, self.table.rowCount()): if self.table.isRowHidden(i): continue test_name = self.table.item(i, 0).text() test_list.append(test_name) if not test_list: test_list = ["all"] results, stats = test(self.session, test_list, profile=self.profile.checkState() == Qt.Checked) cell_widgets = [] for name in results: widget = QWidget() widget_layout = QHBoxLayout(widget) widget_layout.setContentsMargins(0, 0, 0, 0) success_button = get_button("success") fail_button = get_button("fail") skip_button = get_button("skip") error_button = get_button("error") expected_fail_button = get_button("expected fail") unexpected_success_button = get_button("unexpected success") success_count = 0 fail_count = 0 error_count = 0 unexpected_success_count = 0 expected_fail_count = 0 skip_count = 0 success_tooltip = "Successes:\n" fail_tooltip = "Failed tests:\n" error_tooltip = "Errors during test:\n" unexpected_success_tooltip = "Unexpected successes:\n" expected_fail_tooltip = "Expected fails:\n" skip_tooltip = "Skipped tests:\n" for case in results[name]: result, msg = results[name][case] if result == "success": success_count += 1 success_tooltip += "%s.%s: %s\n" % ( case.__class__.__qualname__, case._testMethodName, msg) elif result == "fail": fail_count += 1 fail_tooltip += "%s.%s failed: %s\n" % ( case.__class__.__qualname__, case._testMethodName, msg) elif result == "error": error_count += 1 error_tooltip += "error during %s.%s: %s\n" % ( case.__class__.__qualname__, case._testMethodName, msg) elif result == "expected_failure": expected_fail_count += 1 expected_fail_tooltip += "intended failure during %s.%s: %s\n" % ( case.__class__.__qualname__, case._testMethodName, msg) elif result == "skip": skip_count += 1 skip_tooltip += "%s.%s\n" % (case.__class__.__qualname__, case._testMethodName) elif result == "unexpected_success": unexpected_success_count += 1 unexpected_success_tooltip += "%s.%s should not have worked, but did\n" % ( case.__class__.__qualname__, case._testMethodName) success_tooltip = success_tooltip.strip() fail_tooltip = fail_tooltip.strip() error_tooltip = error_tooltip.strip() expected_fail_tooltip = expected_fail_tooltip.strip() skip_tooltip = skip_tooltip.strip() unexpected_success_tooltip = unexpected_success_tooltip.strip() icon_count = 0 if success_count: success_button.setText("%i" % success_count) success_button.setToolTip(success_tooltip) success_button.clicked.connect( lambda *args, t_name=name, res=success_tooltip: self. tool_window.create_child_window( "successes for %s" % t_name, text=res, window_class=ResultsWindow, )) widget_layout.insertWidget(icon_count, success_button, 1) icon_count += 1 if fail_count: fail_button.setText("%i" % fail_count) fail_button.setToolTip(fail_tooltip) fail_button.clicked.connect( lambda *args, res=fail_tooltip: self.tool_window. create_child_window( "failures for %s" % name, text=res, window_class=ResultsWindow, )) widget_layout.insertWidget(icon_count, fail_button, 1) icon_count += 1 if error_count: error_button.setText("%i" % error_count) error_button.setToolTip(error_tooltip) error_button.clicked.connect( lambda *args, res=error_tooltip: self.tool_window. create_child_window( "errors for %s" % name, text=res, window_class=ResultsWindow, )) widget_layout.insertWidget(icon_count, error_button, 1) icon_count += 1 if unexpected_success_count: unexpected_success_button.setText("%i" % unexpected_success_count) unexpected_success_button.setToolTip( unexpected_success_tooltip) unexpected_success_button.clicked.connect( lambda *args, res=unexpected_success_tooltip: self. tool_window.create_child_window( "unexpected successes for %s" % name, text=res, window_class=ResultsWindow, )) widget_layout.insertWidget(icon_count, unexpected_success_button, 1) icon_count += 1 if expected_fail_count: expected_fail_button.setText("%i" % expected_fail_count) expected_fail_button.setToolTip(expected_fail_tooltip) expected_fail_button.clicked.connect( lambda *args, res=expected_fail_tooltip: self.tool_window. create_child_window( "expected failures for %s" % name, text=res, window_class=ResultsWindow, )) widget_layout.insertWidget(icon_count, expected_fail_button, 1) icon_count += 1 if skip_count: skip_button.setText("%i" % skip_count) skip_button.setToolTip(skip_tooltip) skip_button.clicked.connect( lambda *args, res=skip_tooltip: self.tool_window. create_child_window( "skipped tests for %s" % name, text=res, window_class=ResultsWindow, )) widget_layout.insertWidget(icon_count, skip_button, 1) cell_widgets.append(widget) widget_count = 0 if use_selected: for row in self.table.selectionModel().selectedRows(): if self.table.isRowHidden(row.row()): continue self.table.setCellWidget(row.row(), 1, cell_widgets[widget_count]) self.table.resizeRowToContents(row.row()) widget_count += 1 else: for i in range(0, self.table.rowCount()): if self.table.isRowHidden(i): continue self.table.setCellWidget(i, 1, cell_widgets[widget_count]) # self.table.resizeRowToContents(i) widget_count += 1 if self.profile.checkState() == Qt.Checked: self.tool_window.create_child_window("stats", text=stats, window_class=ResultsWindow)
def __init__(self, parent=None, **kwds): super(StringInputWidget, self).__init__(parent=parent, **kwds) self.le = QLineEdit(self) self.le.setContextMenuPolicy(QtCore.Qt.NoContextMenu) self.setWidget(self.le) self.le.textChanged.connect(lambda val: self.dataSetCallback(val))
class Second(QMainWindow): def __init__(self): super(Second, self).__init__() self.setWindowTitle("Add new device") self.nameLabel = QLabel(self) self.nameLabel.move(10, 10) self.nameLabel.setText("Device name") self.nameEntry = QLineEdit(self) self.nameEntry.move(10, 40) self.nameEntry.resize(100, 30) self.colorLabel = QLabel(self) self.colorLabel.move(120, 10) self.colorLabel.setText("Color cameras") self.colorEntry = QLineEdit(self) self.colorEntry.move(140, 40) self.colorEntry.resize(70, 30) self.colorEntry.setValidator(QtGui.QIntValidator()) self.monoLabel = QLabel(self) self.monoLabel.move(230, 10) self.monoLabel.setText("Mono cameras") self.monoEntry = QLineEdit(self) self.monoEntry.move(250, 40) self.monoEntry.resize(70, 30) self.monoEntry.setValidator(QtGui.QIntValidator()) self.depthPresent = QCheckBox("Include depth", self) self.depthPresent.move(10, 80) self.depthPresent.resize(150, 30) self.depthPresent.stateChanged.connect(self.toggle_depth) self.leftfovLabel = QLabel(self) self.leftfovLabel.move(10, 120) self.leftfovLabel.setText("Left FOV deg.") self.leftfovEntry = QLineEdit(self) self.leftfovEntry.move(180, 120) self.leftfovEntry.resize(140, 30) self.leftfovEntry.setValidator(QtGui.QDoubleValidator()) self.rightfovLabel = QLabel(self) self.rightfovLabel.move(10, 160) self.rightfovLabel.setText("Right FOV deg.") self.rightfovEntry = QLineEdit(self) self.rightfovEntry.move(180, 160) self.rightfovEntry.resize(140, 30) self.rightfovEntry.setValidator(QtGui.QDoubleValidator()) self.rgbfovLabel = QLabel(self) self.rgbfovLabel.move(10, 200) self.rgbfovLabel.setText("RGB FOV deg.") self.rgbfovEntry = QLineEdit(self) self.rgbfovEntry.move(180, 200) self.rgbfovEntry.resize(140, 30) self.rgbfovEntry.setValidator(QtGui.QDoubleValidator()) self.lrdistanceLabel = QLabel(self) self.lrdistanceLabel.move(10, 240) self.lrdistanceLabel.resize(200, 30) self.lrdistanceLabel.setText("Left - Right distance cm.") self.lrdistanceEntry = QLineEdit(self) self.lrdistanceEntry.move(180, 240) self.lrdistanceEntry.resize(140, 30) self.lrdistanceEntry.setValidator(QtGui.QDoubleValidator()) self.lrgbdistanceLabel = QLabel(self) self.lrgbdistanceLabel.move(10, 280) self.lrgbdistanceLabel.resize(200, 30) self.lrgbdistanceLabel.setText("Left - RGB distance cm.") self.lrgbdistanceEntry = QLineEdit(self) self.lrgbdistanceEntry.move(180, 280) self.lrgbdistanceEntry.resize(140, 30) self.lrgbdistanceEntry.setValidator(QtGui.QDoubleValidator()) self.saveButton = QPushButton("Save", self) self.saveButton.resize(100, 30) self.saveButton.clicked.connect(self.save) self.cancelButton = QPushButton("Cancel", self) self.cancelButton.resize(100, 30) self.cancelButton.clicked.connect(self.cancel) self.toggle_depth(False) def toggle_depth(self, checked): if checked: self.leftfovLabel.setVisible(True) self.leftfovEntry.setVisible(True) self.rightfovLabel.setVisible(True) self.rightfovEntry.setVisible(True) self.rgbfovLabel.setVisible(True) self.rgbfovEntry.setVisible(True) self.lrdistanceLabel.setVisible(True) self.lrdistanceEntry.setVisible(True) self.lrgbdistanceLabel.setVisible(True) self.lrgbdistanceEntry.setVisible(True) self.saveButton.move(200, 330) self.cancelButton.move(30, 330) self.resize(330, 380) else: self.leftfovLabel.setVisible(False) self.leftfovEntry.setVisible(False) self.rightfovLabel.setVisible(False) self.rightfovEntry.setVisible(False) self.rgbfovLabel.setVisible(False) self.rgbfovEntry.setVisible(False) self.lrdistanceLabel.setVisible(False) self.lrdistanceEntry.setVisible(False) self.lrgbdistanceLabel.setVisible(False) self.lrgbdistanceEntry.setVisible(False) self.saveButton.move(200, 120) self.cancelButton.move(30, 120) self.resize(330, 170) def save(self, *args, **kwargs): try: data = { "name": self.nameEntry.text(), "color_count": int(self.colorEntry.text()), "mono_count": int(self.monoEntry.text()), } if self.depthPresent.isChecked(): data.update({ "depth": True, "left_fov_deg": float(self.leftfovEntry.text()), "right_fov_deg": float(self.rightfovEntry.text()), "rgb_fov_deg": float(self.rgbfovEntry.text()), "left_to_right_distance_cm": float(self.lrdistanceEntry.text()), "left_to_rgb_distance_cm": float(self.lrgbdistanceEntry.text()), }) append_to_json(data, Path(__file__).parent.parent / Path('custom_devices.json')) self.close() INITIALIZE() self.instance.getRegisteredTools(['NodeBoxTool'])[0].refresh() except Exception as e: QMessageBox.warning(self, "Warning", str(e)) def cancel(self): self.close()
class Info(ToolInstance): help = "https://github.com/QChASM/SEQCROW/wiki/File-Info-Tool" def __init__(self, session, name): super().__init__(session, name) self.tool_window = MainToolWindow(self) self.settings = _InfoSettings(self.session, name) self._build_ui() def _build_ui(self): layout = QVBoxLayout() self.file_selector = FilereaderComboBox(self.session) self.file_selector.currentIndexChanged.connect(self.fill_table) layout.insertWidget(0, self.file_selector, 0) tabs = QTabWidget() self.tabs = tabs layout.insertWidget(1, self.tabs, 1) general_info = QWidget() general_layout = QVBoxLayout(general_info) tabs.addTab(general_info, "general") self.table = QTableWidget() self.table.setColumnCount(2) self.table.setHorizontalHeaderLabels(['Data', 'Value']) self.table.horizontalHeader().setStretchLastSection(False) self.table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Interactive) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) general_layout.insertWidget(1, self.table, 1) self.filter = QLineEdit() self.filter.setPlaceholderText("filter data") self.filter.textChanged.connect(self.apply_filter) self.filter.setClearButtonEnabled(True) general_layout.insertWidget(2, self.filter, 0) freq_info = QWidget() freq_layout = QVBoxLayout(freq_info) tabs.addTab(freq_info, "harmonic frequencies") self.freq_table = QTableWidget() self.freq_table.setColumnCount(4) self.freq_table.setHorizontalHeaderLabels([ "Frequency (cm\u207b\u00b9)", "symmetry", "IR intensity", "force constant (mDyne/\u212B)", ]) self.freq_table.setSortingEnabled(True) self.freq_table.setEditTriggers(QTableWidget.NoEditTriggers) for i in range(0, 4): self.freq_table.resizeColumnToContents(i) self.freq_table.horizontalHeader().setStretchLastSection(False) self.freq_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.freq_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.freq_table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Fixed) self.freq_table.horizontalHeader().setSectionResizeMode( 3, QHeaderView.Stretch) self.freq_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) freq_layout.insertWidget(1, self.freq_table, 1) anharm_info = QWidget() anharm_layout = QVBoxLayout(anharm_info) tabs.addTab(anharm_info, "anharmonic frequencies") anharm_layout.insertWidget(0, QLabel("fundamentals:"), 0) self.fundamental_table = QTableWidget() self.fundamental_table.setColumnCount(3) self.fundamental_table.setHorizontalHeaderLabels([ "Fundamental (cm\u207b\u00b9)", "Δ\u2090\u2099\u2095 (cm\u207b\u00b9)", "IR intensity", ]) self.fundamental_table.setSortingEnabled(True) self.fundamental_table.setEditTriggers(QTableWidget.NoEditTriggers) for i in range(0, 3): self.fundamental_table.resizeColumnToContents(i) self.fundamental_table.horizontalHeader().setStretchLastSection(False) self.fundamental_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.fundamental_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.fundamental_table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Stretch) self.fundamental_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) anharm_layout.insertWidget(1, self.fundamental_table, 1) # self.overtone_table = QTableWidget() # self.overtone_table.setColumnCount(3) # self.overtone_table.setHorizontalHeaderLabels( # [ # "Fundamental (cm\u207b\u00b9)", # "Overtone (cm\u207b\u00b9)", # "IR intensity", # ] # ) # self.overtone_table.setSortingEnabled(True) # self.overtone_table.setEditTriggers(QTableWidget.NoEditTriggers) # for i in range(0, 3): # self.overtone_table.resizeColumnToContents(i) # # self.overtone_table.horizontalHeader().setStretchLastSection(False) # self.overtone_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed) # self.overtone_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Fixed) # self.overtone_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) # # self.overtone_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) # anharm_layout.insertWidget(2, self.overtone_table, 1) anharm_layout.insertWidget(2, QLabel("combinations and overtones:"), 0) self.combo_table = QTableWidget() self.combo_table.setColumnCount(4) self.combo_table.setHorizontalHeaderLabels([ "Fundamental (cm\u207b\u00b9)", "Fundamental (cm\u207b\u00b9)", "Combination (cm\u207b\u00b9)", "IR intensity", ]) self.combo_table.setSortingEnabled(True) self.combo_table.setEditTriggers(QTableWidget.NoEditTriggers) for i in range(0, 3): self.combo_table.resizeColumnToContents(i) self.combo_table.horizontalHeader().setStretchLastSection(False) self.combo_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.combo_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.combo_table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Fixed) self.combo_table.horizontalHeader().setSectionResizeMode( 3, QHeaderView.Stretch) self.combo_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) anharm_layout.insertWidget(3, self.combo_table, 1) menu = QMenuBar() export = menu.addMenu("&Export") copy = QAction("&Copy CSV to clipboard", self.tool_window.ui_area) copy.triggered.connect(self.copy_csv) shortcut = QKeySequence(Qt.CTRL + Qt.Key_C) copy.setShortcut(shortcut) export.addAction(copy) self.copy = copy save = QAction("&Save CSV...", self.tool_window.ui_area) save.triggered.connect(self.save_csv) export.addAction(save) delimiter = export.addMenu("Delimiter") comma = QAction("comma", self.tool_window.ui_area, checkable=True) comma.setChecked(self.settings.delimiter == "comma") comma.triggered.connect(lambda *args, delim="comma": self.settings. __setattr__("delimiter", delim)) delimiter.addAction(comma) tab = QAction("tab", self.tool_window.ui_area, checkable=True) tab.setChecked(self.settings.delimiter == "tab") tab.triggered.connect(lambda *args, delim="tab": self.settings. __setattr__("delimiter", delim)) delimiter.addAction(tab) # space = QAction("space", self.tool_window.ui_area, checkable=True) # space.setChecked(self.settings.delimiter == "space") # space.triggered.connect(lambda *args, delim="space": self.settings.__setattr__("delimiter", delim)) # delimiter.addAction(space) semicolon = QAction("semicolon", self.tool_window.ui_area, checkable=True) semicolon.setChecked(self.settings.delimiter == "semicolon") semicolon.triggered.connect(lambda *args, delim="semicolon": self. settings.__setattr__("delimiter", delim)) delimiter.addAction(semicolon) add_header = QAction("&Include CSV header", self.tool_window.ui_area, checkable=True) add_header.setChecked(self.settings.include_header) add_header.triggered.connect(self.header_check) export.addAction(add_header) tab.triggered.connect( lambda *args, action=semicolon: action.setChecked(False)) semicolon.triggered.connect( lambda *args, action=tab: action.setChecked(False)) archive = QAction("Include archive if present", self.tool_window.ui_area, checkable=True) archive.triggered.connect( lambda checked: setattr(self.settings, "archive", checked)) archive.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) archive.setChecked(self.settings.archive) export.addAction(archive) unit = menu.addMenu("&Units") energy = unit.addMenu("energy") hartree = QAction("Hartree", self.tool_window.ui_area, checkable=True) hartree.setChecked(self.settings.energy == "Hartree") kcal = QAction("kcal/mol", self.tool_window.ui_area, checkable=True) kcal.setChecked(self.settings.energy == "kcal/mol") kjoule = QAction("kJ/mol", self.tool_window.ui_area, checkable=True) kjoule.setChecked(self.settings.energy == "kJ/mol") energy.addAction(hartree) energy.addAction(kcal) energy.addAction(kjoule) hartree.triggered.connect( lambda *args, val="Hartree": setattr(self.settings, "energy", val)) hartree.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) hartree.triggered.connect( lambda *args, action=kcal: action.setChecked(False)) hartree.triggered.connect( lambda *args, action=kjoule: action.setChecked(False)) kcal.triggered.connect(lambda *args, val="kcal/mol": setattr( self.settings, "energy", val)) kcal.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) kcal.triggered.connect( lambda *args, action=hartree: action.setChecked(False)) kcal.triggered.connect( lambda *args, action=kjoule: action.setChecked(False)) kjoule.triggered.connect( lambda *args, val="kJ/mol": setattr(self.settings, "energy", val)) kjoule.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) kjoule.triggered.connect( lambda *args, action=hartree: action.setChecked(False)) kjoule.triggered.connect( lambda *args, action=kcal: action.setChecked(False)) mass = unit.addMenu("mass") kg = QAction("kg", self.tool_window.ui_area, checkable=True) kg.setChecked(self.settings.mass == "kg") amu = QAction("Da", self.tool_window.ui_area, checkable=True) amu.setChecked(self.settings.mass == "Da") mass.addAction(kg) mass.addAction(amu) kg.triggered.connect( lambda *args, val="kg": setattr(self.settings, "mass", val)) kg.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) kg.triggered.connect( lambda *args, action=amu: action.setChecked(False)) amu.triggered.connect( lambda *args, val="Da": setattr(self.settings, "mass", val)) amu.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) amu.triggered.connect( lambda *args, action=kg: action.setChecked(False)) rot_const = unit.addMenu("rotational constants") temperature = QAction("K", self.tool_window.ui_area, checkable=True) temperature.setChecked(self.settings.rot_const == "K") hertz = QAction("GHz", self.tool_window.ui_area, checkable=True) hertz.setChecked(self.settings.rot_const == "GHz") rot_const.addAction(temperature) rot_const.addAction(hertz) temperature.triggered.connect( lambda *args, val="K": setattr(self.settings, "rot_const", val)) temperature.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) temperature.triggered.connect( lambda *args, action=hertz: action.setChecked(False)) hertz.triggered.connect( lambda *args, val="GHz": setattr(self.settings, "rot_const", val)) hertz.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) hertz.triggered.connect( lambda *args, action=temperature: action.setChecked(False)) menu.setNativeMenuBar(False) self._menu = menu layout.setMenuBar(menu) menu.setVisible(True) if len(self.session.filereader_manager.list()) > 0: self.fill_table(0) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None) def header_check(self, state): """user has [un]checked the 'include header' option on the menu""" if state: self.settings.include_header = True else: self.settings.include_header = False def get_csv(self): if self.settings.delimiter == "comma": delim = "," elif self.settings.delimiter == "space": delim = " " elif self.settings.delimiter == "tab": delim = "\t" elif self.settings.delimiter == "semicolon": delim = ";" if self.tabs.currentIndex() == 0: if self.settings.include_header: s = delim.join(["Data", "Value"]) s += "\n" else: s = "" for i in range(0, self.table.rowCount()): if self.table.isRowHidden(i): continue s += delim.join([ item.text().replace("<sub>", "").replace("</sub>", "") for item in [ self.table.item(i, j) if self.table.item(i, j) is not None else self.table.cellWidget(i, j) for j in range(0, 2) ] ]) s += "\n" elif self.tabs.currentIndex() == 1: if self.settings.include_header: s = delim.join([ "Frequency (cm\u207b\u00b9)", "symmetry", "IR intensity", "force constant" ]) s += "\n" else: s = "" for i in range(0, self.freq_table.rowCount()): if self.freq_table.isRowHidden(i): continue s += delim.join([ item.text().replace("<sub>", "").replace("</sub>", "") for item in [ self.freq_table.item(i, j) if self.freq_table. item(i, j) is not None else self.freq_table. cellWidget(i, j) for j in range(0, 4) ] ]) s += "\n" else: if self.settings.include_header: s = delim.join( ["Fundamental (cm\u207b\u00b9)", "Δanh", "IR intensity"]) s += "\n" else: s = "" for i in range(0, self.fundamental_table.rowCount()): if self.fundamental_table.isRowHidden(i): continue s += delim.join([ item.text().replace("<sub>", "").replace("</sub>", "") for item in [ self.fundamental_table.item(i, j) if self. fundamental_table.item(i, j) is not None else self. fundamental_table.cellWidget(i, j) for j in range(0, 3) ] ]) s += "\n" if self.settings.include_header: s += delim.join([ "Fundamental (cm\u207b\u00b9)", "Fundamental (cm\u207b\u00b9)", "Combination (cm\u207b\u00b9)", "IR intensity" ]) s += "\n" else: s += "\n" for i in range(0, self.combo_table.rowCount()): if self.combo_table.isRowHidden(i): continue s += delim.join([ item.text().replace("<sub>", "").replace("</sub>", "") for item in [ self.combo_table.item(i, j) if self.combo_table. item(i, j) is not None else self.combo_table. cellWidget(i, j) for j in range(0, 4) ] ]) s += "\n" return s def copy_csv(self): app = QApplication.instance() clipboard = app.clipboard() csv = self.get_csv() clipboard.setText(csv) self.session.logger.status("copied to clipboard") def save_csv(self): """save data on current tab to CSV file""" filename, _ = QFileDialog.getSaveFileName(filter="CSV Files (*.csv)") if filename: s = self.get_csv() with open(filename, 'w') as f: f.write(s.strip()) self.session.logger.status("saved to %s" % filename) def fill_table(self, ndx): self.table.setRowCount(0) self.freq_table.setRowCount(0) self.fundamental_table.setRowCount(0) # self.overtone_table.setRowCount(0) self.combo_table.setRowCount(0) if ndx < 0: self.fundamental_table.setVisible(False) self.combo_table.setVisible(False) return fr = self.file_selector.currentData() item = QTableWidgetItem() item.setData(Qt.DisplayRole, "name") val = QTableWidgetItem() val.setData(Qt.DisplayRole, fr.name) self.table.insertRow(0) self.table.setItem(0, 0, item) self.table.setItem(0, 1, val) for info in fr.other.keys(): if info == "archive" and not self.settings.archive: continue if any( isinstance(fr.other[info], obj) for obj in [str, float, int]): row = self.table.rowCount() self.table.insertRow(row) item = QTableWidgetItem() info_name = info.replace("_", " ") val = fr.other[info] if info == "mass": info_name += " (%s)" % self.settings.mass if self.settings.mass == "Da": val /= UNIT.AMU_TO_KG elif info == "temperature": info_name += " (K)" elif (any(info == s for s in nrg_infos) or info.lower().endswith("energy") or info.startswith("E(")): if self.settings.energy == "Hartree": info_name += " (E<sub>h</sub>)" else: info_name += " (%s)" % self.settings.energy info_name = info_name.replace("orrelation", "orr.") info_name = info_name.replace("Same-spin", "SS") info_name = info_name.replace("Opposite-spin", "OS") if self.settings.energy == "kcal/mol": val *= UNIT.HART_TO_KCAL elif self.settings.energy == "kJ/mol": val *= 4.184 * UNIT.HART_TO_KCAL val = "%.6f" % val elif info.startswith("optical rotation"): info_name += " (°)" elif any(info == x for x in pg_infos): info_name = info.replace("_", " ") if re.search("\d", val): val = re.sub(r"(\d+)", r"<sub>\1</sub>", val) # gaussian uses * for infinity val = val.replace("*", "<sub>∞</sub>") # psi4 uses _inf_ val = val.replace("_inf_", "<sub>∞</sub>") if any(val.endswith(char) for char in "vhdsiVHDSI"): val = val[:-1] + "<sub>" + val[-1].lower() + "</sub>" if "<sub>" in info_name: self.table.setCellWidget(row, 0, QLabel(info_name)) else: item = QTableWidgetItem() item.setData(Qt.DisplayRole, info_name) self.table.setItem(row, 0, item) value = QTableWidgetItem() val = str(val) if "<sub>" in val: self.table.setCellWidget(row, 1, QLabel(val)) else: value.setData(Qt.DisplayRole, val) self.table.setItem(row, 1, value) elif isinstance(fr.other[info], Theory): theory = fr.other[info] if theory.method is not None: row = self.table.rowCount() self.table.insertRow(row) item = QTableWidgetItem() item.setData(Qt.DisplayRole, "method") self.table.setItem(row, 0, item) value = QTableWidgetItem() value.setData(Qt.DisplayRole, theory.method.name) self.table.setItem(row, 1, value) if theory.basis is not None: if theory.basis.basis: for basis in theory.basis.basis: row = self.table.rowCount() self.table.insertRow(row) item = QTableWidgetItem() if not basis.elements: item.setData(Qt.DisplayRole, "basis set") else: item.setData( Qt.DisplayRole, "basis for %s" % ", ".join(basis.elements)) self.table.setItem(row, 0, item) value = QTableWidgetItem() value.setData(Qt.DisplayRole, basis.name) self.table.setItem(row, 1, value) if theory.basis.ecp: for ecp in theory.basis.ecp: row = self.table.rowCount() self.table.insertRow(row) item = QTableWidgetItem() if ecp.elements is None: item.setData(Qt.DisplayRole, "ECP") else: item.setData(Qt.DisplayRole, "ECP %s" % " ".join(ecp.elements)) self.table.setItem(row, 0, item) value = QTableWidgetItem() value.setData(Qt.DisplayRole, ecp.name) self.table.setItem(row, 1, value) elif (hasattr(fr.other[info], "__iter__") and all(isinstance(x, float) for x in fr.other[info]) and len(fr.other[info]) > 1): row = self.table.rowCount() self.table.insertRow(row) item = QTableWidgetItem() info_name = info.replace("_", " ") vals = fr.other[info] if "rotational_temperature" in info: info_name = info_name.replace( "temperature", "constants (%s)" % self.settings.rot_const) if self.settings.rot_const == "GHz": vals = [ x * PHYSICAL.KB / (PHYSICAL.PLANCK * (10**9)) for x in vals ] item.setData(Qt.DisplayRole, info_name) self.table.setItem(row, 0, item) value = QTableWidgetItem() value.setData(Qt.DisplayRole, ", ".join(["%.4f" % x for x in vals])) self.table.setItem(row, 1, value) if "frequency" in fr.other: self.tabs.setTabEnabled(1, True) freq_data = fr.other['frequency'].data for i, mode in enumerate(freq_data): row = self.freq_table.rowCount() self.freq_table.insertRow(row) freq = FreqTableWidgetItem() freq.setData( Qt.DisplayRole, "%.2f%s" % (abs(mode.frequency), "i" if mode.frequency < 0 else "")) freq.setData(Qt.UserRole, i) self.freq_table.setItem(row, 0, freq) if mode.symmetry: text = mode.symmetry if re.search("\d", text): text = re.sub(r"(\d+)", r"<sub>\1</sub>", text) if text.startswith("SG"): text = "Σ" + text[2:] elif text.startswith("PI"): text = "Π" + text[2:] elif text.startswith("DLT"): text = "Δ" + text[3:] if any(text.endswith(char) for char in "vhdugVHDUG"): text = text[:-1] + "<sub>" + text[-1].lower( ) + "</sub>" label = QLabel(text) label.setAlignment(Qt.AlignCenter) self.freq_table.setCellWidget(row, 1, label) intensity = QTableWidgetItem() if mode.intensity is not None: intensity.setData(Qt.DisplayRole, round(mode.intensity, 2)) self.freq_table.setItem(row, 2, intensity) forcek = QTableWidgetItem() if mode.forcek is not None: forcek.setData(Qt.DisplayRole, round(mode.forcek, 2)) self.freq_table.setItem(row, 3, forcek) if fr.other["frequency"].anharm_data: self.fundamental_table.setVisible(True) self.combo_table.setVisible(True) freq = fr.other["frequency"] self.tabs.setTabEnabled(2, True) anharm_data = sorted( freq.anharm_data, key=lambda x: x.harmonic_frequency, ) for i, mode in enumerate(anharm_data): row = self.fundamental_table.rowCount() self.fundamental_table.insertRow(row) fund = FreqTableWidgetItem() fund.setData( Qt.DisplayRole, "%.2f%s" % (abs(mode.frequency), "i" if mode.frequency < 0 else "")) fund.setData(Qt.UserRole, i) self.fundamental_table.setItem(row, 0, fund) delta_anh = QTableWidgetItem() delta_anh.setData(Qt.DisplayRole, round(mode.delta_anh, 2)) self.fundamental_table.setItem(row, 1, delta_anh) intensity = QTableWidgetItem() if mode.intensity is not None: intensity.setData(Qt.DisplayRole, round(mode.intensity, 2)) self.fundamental_table.setItem(row, 2, intensity) for overtone in mode.overtones: row = self.combo_table.rowCount() self.combo_table.insertRow(row) fund = FreqTableWidgetItem() fund.setData( Qt.DisplayRole, "%.2f%s" % (abs(mode.frequency), "i" if mode.frequency < 0 else "")) fund.setData(Qt.UserRole, i) self.combo_table.setItem(row, 0, fund) fund = FreqTableWidgetItem() fund.setData(Qt.UserRole, i) self.combo_table.setItem(row, 1, fund) ot = FreqTableWidgetItem() ot.setData( Qt.DisplayRole, "%.2f%s" % (abs(overtone.frequency), "i" if overtone.frequency < 0 else "")) ot.setData(Qt.UserRole, i) self.combo_table.setItem(row, 2, ot) intensity = QTableWidgetItem() if overtone.intensity is not None: intensity.setData(Qt.DisplayRole, round(overtone.intensity, 2)) self.combo_table.setItem(row, 3, intensity) for key in mode.combinations: for combination in mode.combinations[key]: row = self.combo_table.rowCount() self.combo_table.insertRow(row) fund = FreqTableWidgetItem() fund.setData( Qt.DisplayRole, "%.2f%s" % (abs(mode.frequency), "i" if mode.frequency < 0 else "")) fund.setData(Qt.UserRole, i) self.combo_table.setItem(row, 0, fund) other_freq = freq.anharm_data[key].frequency fund = FreqTableWidgetItem() fund.setData( Qt.DisplayRole, "%.2f%s" % (abs(other_freq), "i" if other_freq < 0 else "")) fund.setData(Qt.UserRole, i + len(freq.anharm_data) * key) self.combo_table.setItem(row, 1, fund) combo = FreqTableWidgetItem() combo.setData( Qt.DisplayRole, "%.2f%s" % (abs(combination.frequency), "i" if combination.frequency < 0 else "")) combo.setData(Qt.UserRole, i) self.combo_table.setItem(row, 2, combo) intensity = QTableWidgetItem() if combination.intensity is not None: intensity.setData( Qt.DisplayRole, round(combination.intensity, 2)) self.combo_table.setItem(row, 3, intensity) else: self.fundamental_table.setVisible(False) self.combo_table.setVisible(False) self.tabs.setTabEnabled(2, False) else: self.fundamental_table.setVisible(False) self.combo_table.setVisible(False) self.tabs.setTabEnabled(1, False) self.tabs.setTabEnabled(2, False) self.table.resizeColumnToContents(0) self.table.resizeColumnToContents(1) self.freq_table.resizeColumnToContents(0) self.freq_table.resizeColumnToContents(1) self.freq_table.resizeColumnToContents(2) self.apply_filter() def apply_filter(self, text=None): if text is None: text = self.filter.text() if text: text = text.replace("(", "\(") text = text.replace(")", "\)") m = QRegularExpression(text) m.setPatternOptions(QRegularExpression.CaseInsensitiveOption) if m.isValid(): m.optimize() filter = lambda row_num: m.match( self.table.item(row_num, 0).text() if self.table.item(row_num, 0) is not None else self.table. cellWidget(row_num, 0).text().replace("<sub>", "").replace( "</sub>", "")).hasMatch() else: return else: filter = lambda row: True for i in range(0, self.table.rowCount()): self.table.setRowHidden(i, not filter(i)) def delete(self): self.file_selector.deleteLater() return super().delete() def close(self): self.file_selector.deleteLater() return super().close()
class RowTableWidget(QFrame): double_clicked = Signal(object) def __init__(self, auto_resize=False, single_row_select=True, context_menu_callback=None, last_column_stretch=True, has_counters=False, parent=None ): QFrame.__init__(self, parent) self._has_counters = has_counters self.model = None self.table_view = RowTableView(auto_resize, single_row_select, context_menu_callback, last_column_stretch) self.table_view.doubleClicked.connect(self._double_clicked) if has_counters: self.counters = Counters() self.counters.button_clicked.connect(self._counter_clicked) self.search_bar = QLineEdit() self.search_bar.setFixedHeight(SEARCHBAR_HEIGHT) self.search_bar.textChanged.connect(self.set_search_text) self.search_bar.setToolTip("Search bar") self.auto_size_button = QPushButton('<>') self.auto_size_button.setFixedSize(SEARCHBAR_HEIGHT, SEARCHBAR_HEIGHT) self.auto_size_button.clicked.connect(self._auto_size_clicked) self.auto_size_button.setToolTip("Auto size") self.status_label = QLabel(STATUS_LABEL_MESSAGE.format(0, 0)) self.status_label.setFixedWidth(STATUS_LABEL_WIDTH) self.progress_bar = QProgressBar() self.progress_bar.setFormat('') layout = QGridLayout() layout.addWidget(self.search_bar, 0, 0, 1, 3) layout.addWidget(self.auto_size_button, 0, 3) if has_counters: layout.addWidget(self.counters, 1, 0, 1, 2) layout.addWidget(self.table_view, 1, 2, 1, 2) else: layout.addWidget(self.table_view, 1, 0, 1, 4) layout.addWidget(self.status_label, 2, 0) layout.addWidget(self.progress_bar, 2, 1, 1, 3) layout.setColumnStretch(2, 100) self.setLayout(layout) def set_model(self, model): self.model = model self.table_view.setModel(model) model.modelReset.connect(self._set_progress_maximum) model.modelReset.connect(self._update_status) if self._has_counters: model.modelReset.connect(self._update_counters) self._update_counters() model.progress_updated.connect(self._update_progress) self._set_progress_maximum() self._update_status() self.progress_bar.setVisible(model.has_background_callback) @property def selected_rows(self): return [self.model.data(index, Qt.UserRole) for index in self.table_view.selectionModel().selectedIndexes() if index.column() == 0] @property def search_text(self): return self.search_bar.text() def set_search_text(self, text): self.search_bar.blockSignals(True) self.search_bar.setText(text) self.search_bar.blockSignals(False) self.model.set_search_text(text) def _set_progress_maximum(self): self.progress_bar.setMaximum(self.model.progress_max) # do better ? def _update_progress(self, value): self.progress_bar.setValue(value) def _update_status(self): self.status_label.setText(STATUS_LABEL_MESSAGE.format( self.model.rowCount(), self.model.total_row_count )) def _counter_clicked(self, entry, checked_buttons): entries = [entry for entry, active in checked_buttons.items() if active] self.model.set_search_counters(entries) def _update_counters(self): self.counters.set(self.model.counters) def _auto_size_clicked(self): with Hourglass(): self.table_view.resizeColumnsToContents() def _double_clicked(self, index): row = self.model.data(index, Qt.UserRole) self.double_clicked.emit(row) def state(self): header_sizes = list() header = self.table_view.horizontalHeader() for section_index in range(header.count()): header_sizes.append(header.sectionSize(section_index)) return { 'header_sizes': header_sizes, 'search_text': self.search_bar.text() } def load_state(self, state): header = self.table_view.horizontalHeader() for section_index, size in enumerate(state['header_sizes']): header.resizeSection(section_index, size) self.search_bar.setText(state['search_text'])
class SearchableMenu(Menu, object): """ Extends standard QMenu to make it searchable. First action is a QLineEdit used to recursively search on all actions """ def __init__(self, **kwargs): super(SearchableMenu, self).__init__(**kwargs) self._search_action = None self._search_edit = None self.setObjectName(kwargs.get('objectName')) self.setTitle(kwargs.get('title')) self._init_search_edit() def clear(self): """ Extends QMenu clear function """ super(SearchableMenu, self).clear() self._init_search_edit() def set_search_visible(self, flag): """ Sets the visibility of the search edit :param flag: bool """ self._search_action.setVisible(flag) def search_visible(self): """ Returns whether or not search edit is visible :return: bool """ return self._search_action.isVisible() def update_search(self, search_string=None): """ Search all actions for a string tag :param str search_string: tag names separated by spaces (for example, "elem1 elem2" :return: str """ def _recursive_search(menu, search_str): for action in menu.actions(): sub_menu = action.menu() if sub_menu: _recursive_search(sub_menu, search_str) continue elif action.isSeparator(): continue elif isinstance(action, SearchableTaggedAction ) and not action.has_tag(search_str): action.setVisible(False) menu_vis = any(action.isVisible() for action in menu.actions()) menu.menuAction().setVisible(menu_vis) def _recursive_search_by_tags(menu, tags): for action in menu.actions(): sub_menu = action.menu() if sub_menu: _recursive_search_by_tags(sub_menu, tags) continue elif action.isSeparator(): continue elif isinstance(action, SearchableTaggedAction): action.setVisible(action.has_any_tag(tags)) menu_vis = any(action.isVisible() for action in menu.actions()) menu.menuAction().setVisible(menu_vis) search_str = search_string or '' split = search_str.split() if not split: qtutils.recursively_set_menu_actions_visibility(menu=self, state=True) return elif len(split) > 1: _recursive_search_by_tags(menu=self, tags=split) return _recursive_search(menu=self, search_str=split[0]) def _init_search_edit(self): """ Internal function that adds a QLineEdit as the first action in the menu """ self._search_action = QWidgetAction(self) self._search_action.setObjectName('SearchAction') self._search_edit = QLineEdit(self) self._search_edit.setPlaceholderText('Search ...') self._search_edit.textChanged.connect(self._on_update_search) self._search_action.setDefaultWidget(self._search_edit) self.addAction(self._search_action) self.addSeparator() def _on_update_search(self, search_string): """ Internal callback function that is called when the user interacts with the search line edit """ self.update_search(search_string)
def _build_ui(self): layout = QGridLayout() library_tabs = QTabWidget() #ligand tab ligand_tab = QWidget() ligand_layout = QFormLayout(ligand_tab) self.ligand_name = QLineEdit() self.ligand_name.setText("") self.ligand_name.setPlaceholderText("leave blank to preview") self.ligand_name.setToolTip( "name of ligand you are adding to your ligand library\nleave blank to open a new model with just the ligand" ) ligand_layout.addRow("ligand name:", self.ligand_name) ligand_key_atoms = QPushButton("set key atoms to current selection") ligand_key_atoms.clicked.connect(self.update_key_atoms) ligand_key_atoms.setToolTip( "the current selection will be the key atoms for the ligand\nleave blank to automatically determine key atoms" ) ligand_layout.addRow(ligand_key_atoms) libadd_ligand = QPushButton("add current selection to library") libadd_ligand.clicked.connect(self.libadd_ligand) ligand_layout.addRow(libadd_ligand) #substituent tab sub_tab = QWidget() sub_layout = QFormLayout(sub_tab) self.sub_name = QLineEdit() self.sub_name.setText("") self.sub_name.setPlaceholderText("leave blank to preview") self.sub_name.setToolTip( "name of substituent you are adding to your substituent library\nleave blank to open a new model with just the substituent" ) sub_layout.addRow("substituent name:", self.sub_name) self.sub_confs = QSpinBox() self.sub_confs.setMinimum(1) sub_layout.addRow("number of conformers:", self.sub_confs) self.sub_angle = QSpinBox() self.sub_angle.setRange(0, 180) self.sub_angle.setSingleStep(30) sub_layout.addRow("angle between conformers:", self.sub_angle) libadd_sub = QPushButton("add current selection to library") libadd_sub.clicked.connect(self.libadd_substituent) sub_layout.addRow(libadd_sub) #ring tab ring_tab = QWidget() ring_layout = QFormLayout(ring_tab) self.ring_name = QLineEdit() self.ring_name.setText("") self.ring_name.setPlaceholderText("leave blank to preview") self.ring_name.setToolTip( "name of ring you are adding to your ring library\nleave blank to open a new model with just the ring" ) ring_layout.addRow("ring name:", self.ring_name) libadd_ring = QPushButton("add ring with selected walk to library") libadd_ring.clicked.connect(self.libadd_ring) ring_layout.addRow(libadd_ring) library_tabs.addTab(sub_tab, "substituent") library_tabs.addTab(ring_tab, "ring") library_tabs.addTab(ligand_tab, "ligand") self.library_tabs = library_tabs layout.addWidget(library_tabs) whats_this = QLabel() whats_this.setText( "<a href=\"req\" style=\"text-decoration: none;\">what's this?</a>" ) whats_this.setTextFormat(Qt.RichText) whats_this.setTextInteractionFlags(Qt.TextBrowserInteraction) whats_this.linkActivated.connect(self.open_link) whats_this.setToolTip( "click for more information about AaronTools libraries") layout.addWidget(whats_this) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None)
class LibAdd(ToolInstance): help = "https://github.com/QChASM/SEQCROW/wiki/Add-to-Personal-Library-Tool" SESSION_ENDURING = False SESSION_SAVE = False def __init__(self, session, name): super().__init__(session, name) from chimerax.ui import MainToolWindow self.tool_window = MainToolWindow(self) self.key_atomspec = [] self._build_ui() def _build_ui(self): layout = QGridLayout() library_tabs = QTabWidget() #ligand tab ligand_tab = QWidget() ligand_layout = QFormLayout(ligand_tab) self.ligand_name = QLineEdit() self.ligand_name.setText("") self.ligand_name.setPlaceholderText("leave blank to preview") self.ligand_name.setToolTip( "name of ligand you are adding to your ligand library\nleave blank to open a new model with just the ligand" ) ligand_layout.addRow("ligand name:", self.ligand_name) ligand_key_atoms = QPushButton("set key atoms to current selection") ligand_key_atoms.clicked.connect(self.update_key_atoms) ligand_key_atoms.setToolTip( "the current selection will be the key atoms for the ligand\nleave blank to automatically determine key atoms" ) ligand_layout.addRow(ligand_key_atoms) libadd_ligand = QPushButton("add current selection to library") libadd_ligand.clicked.connect(self.libadd_ligand) ligand_layout.addRow(libadd_ligand) #substituent tab sub_tab = QWidget() sub_layout = QFormLayout(sub_tab) self.sub_name = QLineEdit() self.sub_name.setText("") self.sub_name.setPlaceholderText("leave blank to preview") self.sub_name.setToolTip( "name of substituent you are adding to your substituent library\nleave blank to open a new model with just the substituent" ) sub_layout.addRow("substituent name:", self.sub_name) self.sub_confs = QSpinBox() self.sub_confs.setMinimum(1) sub_layout.addRow("number of conformers:", self.sub_confs) self.sub_angle = QSpinBox() self.sub_angle.setRange(0, 180) self.sub_angle.setSingleStep(30) sub_layout.addRow("angle between conformers:", self.sub_angle) libadd_sub = QPushButton("add current selection to library") libadd_sub.clicked.connect(self.libadd_substituent) sub_layout.addRow(libadd_sub) #ring tab ring_tab = QWidget() ring_layout = QFormLayout(ring_tab) self.ring_name = QLineEdit() self.ring_name.setText("") self.ring_name.setPlaceholderText("leave blank to preview") self.ring_name.setToolTip( "name of ring you are adding to your ring library\nleave blank to open a new model with just the ring" ) ring_layout.addRow("ring name:", self.ring_name) libadd_ring = QPushButton("add ring with selected walk to library") libadd_ring.clicked.connect(self.libadd_ring) ring_layout.addRow(libadd_ring) library_tabs.addTab(sub_tab, "substituent") library_tabs.addTab(ring_tab, "ring") library_tabs.addTab(ligand_tab, "ligand") self.library_tabs = library_tabs layout.addWidget(library_tabs) whats_this = QLabel() whats_this.setText( "<a href=\"req\" style=\"text-decoration: none;\">what's this?</a>" ) whats_this.setTextFormat(Qt.RichText) whats_this.setTextInteractionFlags(Qt.TextBrowserInteraction) whats_this.linkActivated.connect(self.open_link) whats_this.setToolTip( "click for more information about AaronTools libraries") layout.addWidget(whats_this) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None) def update_key_atoms(self): selection = selected_atoms(self.session) if not selection.single_structure: raise RuntimeError("selected atoms must be on the same model") else: self.key_atomspec = selection self.tool_window.status("key atoms set to %s" % " ".join(atom.atomspec for atom in selection)) def libadd_ligand(self): """add ligand to library or open it in a new model""" selection = selected_atoms(self.session) if not selection.single_structure: raise RuntimeError("selected atoms must be on the same model") rescol = ResidueCollection(selection[0].structure) ligand_atoms = [ atom for atom in rescol.atoms if atom.chix_atom in selection ] key_chix_atoms = [ atom for atom in self.key_atomspec if not atom.deleted ] if len(key_chix_atoms) < 1: key_atoms = set([]) for atom in ligand_atoms: for atom2 in atom.connected: if atom2 not in ligand_atoms: key_atoms.add(atom) else: key_atoms = rescol.find( [AtomSpec(atom.atomspec) for atom in key_chix_atoms]) if len(key_atoms) < 1: raise RuntimeError("no key atoms could be determined") lig_name = self.ligand_name.text() ligand = Component(ligand_atoms, name=lig_name, key_atoms=key_atoms) ligand.comment = "K:%s" % ",".join( [str(ligand.atoms.index(atom) + 1) for atom in key_atoms]) if len(lig_name) == 0: chimerax_ligand = ResidueCollection(ligand).get_chimera( self.session) chimerax_ligand.name = "ligand preview" self.session.models.add([chimerax_ligand]) bild_obj = key_atom_highlight(ligand, [0.2, 0.5, 0.8, 0.5], self.session) self.session.models.add(bild_obj, parent=chimerax_ligand) else: check_aaronlib_dir() filename = os.path.join(AARONLIB, "Ligands", lig_name + ".xyz") if os.path.exists(filename): exists_warning = QMessageBox() exists_warning.setIcon(QMessageBox.Warning) exists_warning.setText( "%s already exists.\nWould you like to overwrite?" % filename) exists_warning.setStandardButtons(QMessageBox.Yes | QMessageBox.No) rv = exists_warning.exec_() if rv == QMessageBox.Yes: ligand.write(outfile=filename) self.tool_window.status("%s added to ligand library" % lig_name) else: self.tool_window.status( "%s has not been added to ligand library" % lig_name) else: ligand.write(outfile=filename) self.tool_window.status("%s added to ligand library" % lig_name) def libadd_ring(self): """add ring to library or open it in a new model""" selection = self.session.seqcrow_ordered_selection_manager.selection if not selection.single_structure: raise RuntimeError("selected atoms must be on the same model") rescol = ResidueCollection(selection[0].structure) walk_atoms = rescol.find( [AtomSpec(atom.atomspec) for atom in selection]) if len(walk_atoms) < 1: raise RuntimeError("no walk direction could be determined") ring_name = self.ring_name.text() ring = Ring(rescol, name=ring_name, end=walk_atoms) ring.comment = "E:%s" % ",".join( [str(rescol.atoms.index(atom) + 1) for atom in walk_atoms]) if len(ring_name) == 0: chimerax_ring = ResidueCollection(ring).get_chimera(self.session) chimerax_ring.name = "ring preview" self.session.models.add([chimerax_ring]) bild_obj = show_walk_highlight(ring, chimerax_ring, [0.9, 0.4, 0.3, 0.9], self.session) self.session.models.add(bild_obj, parent=chimerax_ring) else: check_aaronlib_dir() filename = os.path.join(AARONLIB, "Rings", ring_name + ".xyz") if os.path.exists(filename): exists_warning = QMessageBox() exists_warning.setIcon(QMessageBox.Warning) exists_warning.setText( "%s already exists.\nWould you like to overwrite?" % filename) exists_warning.setStandardButtons(QMessageBox.Yes | QMessageBox.No) rv = exists_warning.exec_() if rv == QMessageBox.Yes: ring.write(outfile=filename) self.tool_window.status("%s added to ring library" % ring_name) else: self.tool_window.status( "%s has not been added to ring library" % ring_name) else: ring.write(outfile=filename) self.tool_window.status("%s added to ring library" % ring_name) def libadd_substituent(self): """add ligand to library or open it in a new model""" selection = selected_atoms(self.session) if not selection.single_structure: raise RuntimeError("selected atoms must be on the same model") residues = [] for atom in selection: if atom.residue not in residues: residues.append(atom.residue) rescol = ResidueCollection(selection[0].structure, convert_residues=residues) substituent_atoms = [ atom for atom in rescol.atoms if atom.chix_atom in selection ] start = None avoid = None for atom in substituent_atoms: for atom2 in atom.connected: if atom2 not in substituent_atoms: if start is None: start = atom avoid = atom2 else: raise RuntimeError( "substituent must only have one connection to the molecule" ) if start is None: raise RuntimeError( "substituent is not connected to a larger molecule") substituent_atoms.remove(start) substituent_atoms.insert(0, start) sub_name = self.sub_name.text() confs = self.sub_confs.value() angle = self.sub_angle.value() comment = "CF:%i,%i" % (confs, angle) if len(sub_name) == 0: sub = Substituent(substituent_atoms, name="test", conf_num=confs, conf_angle=angle) else: sub = Substituent(substituent_atoms, name=sub_name, conf_num=confs, conf_angle=angle) sub.comment = comment #align substituent bond to x axis sub.coord_shift(-avoid.coords) x_axis = np.array([1., 0., 0.]) n = np.linalg.norm(start.coords) vb = start.coords / n d = np.linalg.norm(vb - x_axis) theta = np.arccos((d**2 - 2) / -2) vx = np.cross(vb, x_axis) sub.rotate(vx, theta) add = False if len(sub_name) == 0: chimerax_sub = ResidueCollection(sub).get_chimera(self.session) chimerax_sub.name = "substituent preview" self.session.models.add([chimerax_sub]) bild_obj = ghost_connection_highlight( sub, [0.60784, 0.145098, 0.70196, 0.5], self.session) self.session.models.add(bild_obj, parent=chimerax_sub) else: check_aaronlib_dir() filename = os.path.join(AARONLIB, "Subs", sub_name + ".xyz") if os.path.exists(filename): exists_warning = QMessageBox() exists_warning.setIcon(QMessageBox.Warning) exists_warning.setText( "%s already exists.\nWould you like to overwrite?" % filename) exists_warning.setStandardButtons(QMessageBox.Yes | QMessageBox.No) rv = exists_warning.exec_() if rv == QMessageBox.Yes: add = True else: self.tool_window.status( "%s has not been added to substituent library" % sub_name) else: add = True if add: sub.write(outfile=filename) self.tool_window.status("%s added to substituent library" % sub_name) register_selectors(self.session.logger, sub_name) if self.session.ui.is_gui: if (sub_name not in ELEMENTS and sub_name[0].isalpha() and (len(sub_name) > 1 and not any(not (c.isalnum() or c in "+-") for c in sub_name[1:]))): add_submenu = self.session.ui.main_window.add_select_submenu add_selector = self.session.ui.main_window.add_menu_selector substituent_menu = add_submenu(['Che&mistry'], 'Substituents') add_selector(substituent_menu, sub_name, sub_name) def display_help(self): """Show the help for this tool in the help viewer.""" from chimerax.core.commands import run run(self.session, 'open %s' % self.help if self.help is not None else "") def open_link(self, *args): if self.library_tabs.currentIndex() == 0: link = "https://github.com/QChASM/AaronTools.py/wiki/AaronTools-Libraries#substituents" elif self.library_tabs.currentIndex() == 1: link = "https://github.com/QChASM/AaronTools.py/wiki/AaronTools-Libraries#rings" elif self.library_tabs.currentIndex() == 2: link = "https://github.com/QChASM/AaronTools.py/wiki/AaronTools-Libraries#ligands" run(self.session, "open %s" % link)
class StringEditor(BaseEditor, object): attr_type = 'str' def __init__(self, parent=None, **kwargs): super(StringEditor, self).__init__(parent=parent, **kwargs) self._default_value = "" self._clean_value = kwargs.get('clean', True) self.value_line = QLineEdit(self) reg_exp = QRegExp('^([a-zA-Z0-9_]+)') self.main_layout.addWidget(self.value_line) self.value_line.textEdited.connect(self._validate_text) self.value_line.editingFinished.connect(self.OnValueUpdated) self.value_line.returnPressed.connect(self.OnValueUpdated) def get_value(self): return str(self.value_line.text()) value = property(get_value) def initialize_editor(self): editor_value = self.default_value node_values = self.values if node_values: if len(node_values) > 1: pass elif len(node_values) == 1: if node_values[0]: editor_value = node_values[0] self.value_line.blockSignals(True) self.value_line.setText(str(editor_value)) self.value_line.blockSignals(False) def set_connected(self, conn): if conn != self._connection: self._connection = conn self.value_line.setText(conn) self.value_line.setEnabled(False) self.value_line.setProperty('class', 'Connected') def _validate_text(self, text): """ Validates the given value and update the current text :param text: str, text to validate """ current_text = self.value if self._clean_value: cursor_pos = self.value_line.cursorPosition() cleaned = string_utils.clean_string(text=text) self.value_line.blockSignals(True) self.value_line.setText(cleaned) self.value_line.blockSignals(False) self.value_line.setCursorPosition(cursor_pos)
def __init__(self, settings, parent=None, description=None, pstvOnly=True): super(ConfigDialog, self).__init__(parent) self.setWindowTitle("Configure source") self.layout = QGridLayout(self) row = 0 self.widgets = {} self.settings = settings # Settings should be a dictionary for name, val in settings.items(): label = QLabel(self) label.setText(str(name)) self.layout.addWidget(label, row, 0, 1, 1) # Check the type of each setting, and create widgets accordingly if isinstance(val, str): # A string of some kind widget = QLineEdit(self) widget.setText(val) elif isinstance(val, list): # A list of alternative values, first is selected print("List: ", name) continue elif isinstance(val, bool): widget = QCheckBox(self) if val: widget.setCheckState(Qt.CheckState.Checked) else: widget.setCheckState(Qt.CheckState.Unchecked) elif isinstance(val, int): widget = QLineEdit(self) widget.setInputMask("9000000") widget.setText(str(val).strip()) elif isinstance(val, float): widget = QLineEdit(self) if pstvOnly: widget.setInputMask("0.000") widget.setText(str(val).strip()) else: print("Ignoring: " + name) continue widget.config = name self.widgets[name] = widget self.layout.addWidget(widget, row, 1, 1, 1) row += 1 # Add OK and Cancel buttons buttonbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttonbox.accepted.connect(self.getValues) buttonbox.rejected.connect(self.reject) self.layout.addWidget(buttonbox, row, 1, 2, 1)
def addAttributeSlot(self): """ Adds a new attribute (column) to the table """ dialog = QDialog(self) dialog.setModal(True) dialog.setWindowTitle('Add Attribute') layout = QVBoxLayout() dialog.setLayout(layout) form = QFormLayout() nameBox = QLineEdit() typeCombo = QComboBox() for attrType in _attrTypes: typeName = partio.TypeName(attrType) typeCombo.addItem(typeName) typeCombo.setCurrentIndex(partio.FLOAT) countBox = QLineEdit() countBox.setValidator(QIntValidator()) countBox.setText('1') fixedCheckbox = QCheckBox() valueBox = QLineEdit() valueBox.setText('0') form.addRow('Name:', nameBox) form.addRow('Type:', typeCombo) form.addRow('Count:', countBox) form.addRow('Fixed:', fixedCheckbox) form.addRow('Default Value:', valueBox) layout.addLayout(form) buttons = QHBoxLayout() layout.addLayout(buttons) add = QPushButton('Add') add.clicked.connect(dialog.accept) buttons.addWidget(add) cancel = QPushButton('Cancel') cancel.clicked.connect(dialog.reject) buttons.addWidget(cancel) if not dialog.exec_(): return name = str(nameBox.text()) if not name: print 'Please supply a name for the new attribute' # TODO: prompt return attrType = typeCombo.currentIndex() count = int(countBox.text()) fixed = fixedCheckbox.isChecked() values = list(str(valueBox.text()).strip().split()) for i in range(count): if i < len(values): value = values[i] else: value = values[-1] if attrType == partio.INT or attrType == partio.INDEXEDSTR: values[i] = int(value) elif attrType == partio.FLOAT or attrType == partio.VECTOR: values[i] = float(value) # pylint:disable=R0204 else: values[i] = 0.0 # pylint:disable=R0204 value = tuple(values) self.data.addAttribute(name, attrType, count, fixed, value)
def newProgField(self, *args): self.lineEditProgs.append(QLineEdit(self)) self.progLayout.addWidget(self.lineEditProgs[len(self.lineEditProgs)-1]) self.lineEditExts.append(QLineEdit(self)) self.extLayout.addWidget(self.lineEditExts[len(self.lineEditExts)-1])
def _build_ui(self): layout = QVBoxLayout() self.file_selector = FilereaderComboBox(self.session) self.file_selector.currentIndexChanged.connect(self.fill_table) layout.insertWidget(0, self.file_selector, 0) tabs = QTabWidget() self.tabs = tabs layout.insertWidget(1, self.tabs, 1) general_info = QWidget() general_layout = QVBoxLayout(general_info) tabs.addTab(general_info, "general") self.table = QTableWidget() self.table.setColumnCount(2) self.table.setHorizontalHeaderLabels(['Data', 'Value']) self.table.horizontalHeader().setStretchLastSection(False) self.table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Interactive) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) general_layout.insertWidget(1, self.table, 1) self.filter = QLineEdit() self.filter.setPlaceholderText("filter data") self.filter.textChanged.connect(self.apply_filter) self.filter.setClearButtonEnabled(True) general_layout.insertWidget(2, self.filter, 0) freq_info = QWidget() freq_layout = QVBoxLayout(freq_info) tabs.addTab(freq_info, "harmonic frequencies") self.freq_table = QTableWidget() self.freq_table.setColumnCount(4) self.freq_table.setHorizontalHeaderLabels([ "Frequency (cm\u207b\u00b9)", "symmetry", "IR intensity", "force constant (mDyne/\u212B)", ]) self.freq_table.setSortingEnabled(True) self.freq_table.setEditTriggers(QTableWidget.NoEditTriggers) for i in range(0, 4): self.freq_table.resizeColumnToContents(i) self.freq_table.horizontalHeader().setStretchLastSection(False) self.freq_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.freq_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.freq_table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Fixed) self.freq_table.horizontalHeader().setSectionResizeMode( 3, QHeaderView.Stretch) self.freq_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) freq_layout.insertWidget(1, self.freq_table, 1) anharm_info = QWidget() anharm_layout = QVBoxLayout(anharm_info) tabs.addTab(anharm_info, "anharmonic frequencies") anharm_layout.insertWidget(0, QLabel("fundamentals:"), 0) self.fundamental_table = QTableWidget() self.fundamental_table.setColumnCount(3) self.fundamental_table.setHorizontalHeaderLabels([ "Fundamental (cm\u207b\u00b9)", "Δ\u2090\u2099\u2095 (cm\u207b\u00b9)", "IR intensity", ]) self.fundamental_table.setSortingEnabled(True) self.fundamental_table.setEditTriggers(QTableWidget.NoEditTriggers) for i in range(0, 3): self.fundamental_table.resizeColumnToContents(i) self.fundamental_table.horizontalHeader().setStretchLastSection(False) self.fundamental_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.fundamental_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.fundamental_table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Stretch) self.fundamental_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) anharm_layout.insertWidget(1, self.fundamental_table, 1) # self.overtone_table = QTableWidget() # self.overtone_table.setColumnCount(3) # self.overtone_table.setHorizontalHeaderLabels( # [ # "Fundamental (cm\u207b\u00b9)", # "Overtone (cm\u207b\u00b9)", # "IR intensity", # ] # ) # self.overtone_table.setSortingEnabled(True) # self.overtone_table.setEditTriggers(QTableWidget.NoEditTriggers) # for i in range(0, 3): # self.overtone_table.resizeColumnToContents(i) # # self.overtone_table.horizontalHeader().setStretchLastSection(False) # self.overtone_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed) # self.overtone_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Fixed) # self.overtone_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) # # self.overtone_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) # anharm_layout.insertWidget(2, self.overtone_table, 1) anharm_layout.insertWidget(2, QLabel("combinations and overtones:"), 0) self.combo_table = QTableWidget() self.combo_table.setColumnCount(4) self.combo_table.setHorizontalHeaderLabels([ "Fundamental (cm\u207b\u00b9)", "Fundamental (cm\u207b\u00b9)", "Combination (cm\u207b\u00b9)", "IR intensity", ]) self.combo_table.setSortingEnabled(True) self.combo_table.setEditTriggers(QTableWidget.NoEditTriggers) for i in range(0, 3): self.combo_table.resizeColumnToContents(i) self.combo_table.horizontalHeader().setStretchLastSection(False) self.combo_table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.combo_table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.combo_table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Fixed) self.combo_table.horizontalHeader().setSectionResizeMode( 3, QHeaderView.Stretch) self.combo_table.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) anharm_layout.insertWidget(3, self.combo_table, 1) menu = QMenuBar() export = menu.addMenu("&Export") copy = QAction("&Copy CSV to clipboard", self.tool_window.ui_area) copy.triggered.connect(self.copy_csv) shortcut = QKeySequence(Qt.CTRL + Qt.Key_C) copy.setShortcut(shortcut) export.addAction(copy) self.copy = copy save = QAction("&Save CSV...", self.tool_window.ui_area) save.triggered.connect(self.save_csv) export.addAction(save) delimiter = export.addMenu("Delimiter") comma = QAction("comma", self.tool_window.ui_area, checkable=True) comma.setChecked(self.settings.delimiter == "comma") comma.triggered.connect(lambda *args, delim="comma": self.settings. __setattr__("delimiter", delim)) delimiter.addAction(comma) tab = QAction("tab", self.tool_window.ui_area, checkable=True) tab.setChecked(self.settings.delimiter == "tab") tab.triggered.connect(lambda *args, delim="tab": self.settings. __setattr__("delimiter", delim)) delimiter.addAction(tab) # space = QAction("space", self.tool_window.ui_area, checkable=True) # space.setChecked(self.settings.delimiter == "space") # space.triggered.connect(lambda *args, delim="space": self.settings.__setattr__("delimiter", delim)) # delimiter.addAction(space) semicolon = QAction("semicolon", self.tool_window.ui_area, checkable=True) semicolon.setChecked(self.settings.delimiter == "semicolon") semicolon.triggered.connect(lambda *args, delim="semicolon": self. settings.__setattr__("delimiter", delim)) delimiter.addAction(semicolon) add_header = QAction("&Include CSV header", self.tool_window.ui_area, checkable=True) add_header.setChecked(self.settings.include_header) add_header.triggered.connect(self.header_check) export.addAction(add_header) tab.triggered.connect( lambda *args, action=semicolon: action.setChecked(False)) semicolon.triggered.connect( lambda *args, action=tab: action.setChecked(False)) archive = QAction("Include archive if present", self.tool_window.ui_area, checkable=True) archive.triggered.connect( lambda checked: setattr(self.settings, "archive", checked)) archive.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) archive.setChecked(self.settings.archive) export.addAction(archive) unit = menu.addMenu("&Units") energy = unit.addMenu("energy") hartree = QAction("Hartree", self.tool_window.ui_area, checkable=True) hartree.setChecked(self.settings.energy == "Hartree") kcal = QAction("kcal/mol", self.tool_window.ui_area, checkable=True) kcal.setChecked(self.settings.energy == "kcal/mol") kjoule = QAction("kJ/mol", self.tool_window.ui_area, checkable=True) kjoule.setChecked(self.settings.energy == "kJ/mol") energy.addAction(hartree) energy.addAction(kcal) energy.addAction(kjoule) hartree.triggered.connect( lambda *args, val="Hartree": setattr(self.settings, "energy", val)) hartree.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) hartree.triggered.connect( lambda *args, action=kcal: action.setChecked(False)) hartree.triggered.connect( lambda *args, action=kjoule: action.setChecked(False)) kcal.triggered.connect(lambda *args, val="kcal/mol": setattr( self.settings, "energy", val)) kcal.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) kcal.triggered.connect( lambda *args, action=hartree: action.setChecked(False)) kcal.triggered.connect( lambda *args, action=kjoule: action.setChecked(False)) kjoule.triggered.connect( lambda *args, val="kJ/mol": setattr(self.settings, "energy", val)) kjoule.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) kjoule.triggered.connect( lambda *args, action=hartree: action.setChecked(False)) kjoule.triggered.connect( lambda *args, action=kcal: action.setChecked(False)) mass = unit.addMenu("mass") kg = QAction("kg", self.tool_window.ui_area, checkable=True) kg.setChecked(self.settings.mass == "kg") amu = QAction("Da", self.tool_window.ui_area, checkable=True) amu.setChecked(self.settings.mass == "Da") mass.addAction(kg) mass.addAction(amu) kg.triggered.connect( lambda *args, val="kg": setattr(self.settings, "mass", val)) kg.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) kg.triggered.connect( lambda *args, action=amu: action.setChecked(False)) amu.triggered.connect( lambda *args, val="Da": setattr(self.settings, "mass", val)) amu.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) amu.triggered.connect( lambda *args, action=kg: action.setChecked(False)) rot_const = unit.addMenu("rotational constants") temperature = QAction("K", self.tool_window.ui_area, checkable=True) temperature.setChecked(self.settings.rot_const == "K") hertz = QAction("GHz", self.tool_window.ui_area, checkable=True) hertz.setChecked(self.settings.rot_const == "GHz") rot_const.addAction(temperature) rot_const.addAction(hertz) temperature.triggered.connect( lambda *args, val="K": setattr(self.settings, "rot_const", val)) temperature.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) temperature.triggered.connect( lambda *args, action=hertz: action.setChecked(False)) hertz.triggered.connect( lambda *args, val="GHz": setattr(self.settings, "rot_const", val)) hertz.triggered.connect( lambda *args: self.fill_table(self.file_selector.count() - 1)) hertz.triggered.connect( lambda *args, action=temperature: action.setChecked(False)) menu.setNativeMenuBar(False) self._menu = menu layout.setMenuBar(menu) menu.setVisible(True) if len(self.session.filereader_manager.list()) > 0: self.fill_table(0) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None)
def __init__(self): super(Second, self).__init__() self.setWindowTitle("Add new device") self.nameLabel = QLabel(self) self.nameLabel.move(10, 10) self.nameLabel.setText("Device name") self.nameEntry = QLineEdit(self) self.nameEntry.move(10, 40) self.nameEntry.resize(100, 30) self.colorLabel = QLabel(self) self.colorLabel.move(120, 10) self.colorLabel.setText("Color cameras") self.colorEntry = QLineEdit(self) self.colorEntry.move(140, 40) self.colorEntry.resize(70, 30) self.colorEntry.setValidator(QtGui.QIntValidator()) self.monoLabel = QLabel(self) self.monoLabel.move(230, 10) self.monoLabel.setText("Mono cameras") self.monoEntry = QLineEdit(self) self.monoEntry.move(250, 40) self.monoEntry.resize(70, 30) self.monoEntry.setValidator(QtGui.QIntValidator()) self.depthPresent = QCheckBox("Include depth", self) self.depthPresent.move(10, 80) self.depthPresent.resize(150, 30) self.depthPresent.stateChanged.connect(self.toggle_depth) self.leftfovLabel = QLabel(self) self.leftfovLabel.move(10, 120) self.leftfovLabel.setText("Left FOV deg.") self.leftfovEntry = QLineEdit(self) self.leftfovEntry.move(180, 120) self.leftfovEntry.resize(140, 30) self.leftfovEntry.setValidator(QtGui.QDoubleValidator()) self.rightfovLabel = QLabel(self) self.rightfovLabel.move(10, 160) self.rightfovLabel.setText("Right FOV deg.") self.rightfovEntry = QLineEdit(self) self.rightfovEntry.move(180, 160) self.rightfovEntry.resize(140, 30) self.rightfovEntry.setValidator(QtGui.QDoubleValidator()) self.rgbfovLabel = QLabel(self) self.rgbfovLabel.move(10, 200) self.rgbfovLabel.setText("RGB FOV deg.") self.rgbfovEntry = QLineEdit(self) self.rgbfovEntry.move(180, 200) self.rgbfovEntry.resize(140, 30) self.rgbfovEntry.setValidator(QtGui.QDoubleValidator()) self.lrdistanceLabel = QLabel(self) self.lrdistanceLabel.move(10, 240) self.lrdistanceLabel.resize(200, 30) self.lrdistanceLabel.setText("Left - Right distance cm.") self.lrdistanceEntry = QLineEdit(self) self.lrdistanceEntry.move(180, 240) self.lrdistanceEntry.resize(140, 30) self.lrdistanceEntry.setValidator(QtGui.QDoubleValidator()) self.lrgbdistanceLabel = QLabel(self) self.lrgbdistanceLabel.move(10, 280) self.lrgbdistanceLabel.resize(200, 30) self.lrgbdistanceLabel.setText("Left - RGB distance cm.") self.lrgbdistanceEntry = QLineEdit(self) self.lrgbdistanceEntry.move(180, 280) self.lrgbdistanceEntry.resize(140, 30) self.lrgbdistanceEntry.setValidator(QtGui.QDoubleValidator()) self.saveButton = QPushButton("Save", self) self.saveButton.resize(100, 30) self.saveButton.clicked.connect(self.save) self.cancelButton = QPushButton("Cancel", self) self.cancelButton.resize(100, 30) self.cancelButton.clicked.connect(self.cancel) self.toggle_depth(False)
class MainWindow(QMainWindow): def __init__(self, url): super().__init__() self.setAttribute(Qt.WA_DeleteOnClose, True) self.progress = 0 f = QFile() f.setFileName(":/jquery.min.js") f.open(QIODevice.ReadOnly) self.jQuery = f.readAll().data().decode() self.jQuery += "\nvar qt = { 'jQuery': jQuery.noConflict(true) };" f.close() self.view = QWebEngineView(self) self.view.load(url) self.view.loadFinished.connect(self.adjustLocation) self.view.titleChanged.connect(self.adjustTitle) self.view.loadProgress.connect(self.setProgress) self.view.loadFinished.connect(self.finishLoading) self.locationEdit = QLineEdit(self) self.locationEdit.setSizePolicy( QSizePolicy.Expanding, self.locationEdit.sizePolicy().verticalPolicy()) self.locationEdit.returnPressed.connect(self.changeLocation) toolBar = self.addToolBar(self.tr("Navigation")) toolBar.addAction(self.view.pageAction(QWebEnginePage.Back)) toolBar.addAction(self.view.pageAction(QWebEnginePage.Forward)) toolBar.addAction(self.view.pageAction(QWebEnginePage.Reload)) toolBar.addAction(self.view.pageAction(QWebEnginePage.Stop)) toolBar.addWidget(self.locationEdit) viewMenu = self.menuBar().addMenu(self.tr("&View")) viewSourceAction = QAction(self.tr("Page Source"), self) viewSourceAction.triggered.connect(self.viewSource) viewMenu.addAction(viewSourceAction) effectMenu = self.menuBar().addMenu(self.tr("&Effect")) effectMenu.addAction(self.tr("Highlight all links"), self.highlightAllLinks) self.rotateAction = QAction(self) self.rotateAction.setIcon(self.style().standardIcon( QStyle.SP_FileDialogDetailedView)) self.rotateAction.setCheckable(True) self.rotateAction.setText(self.tr("Turn images upside down")) self.rotateAction.toggled.connect(self.rotateImages) effectMenu.addAction(self.rotateAction) toolsMenu = self.menuBar().addMenu(self.tr("&Tools")) toolsMenu.addAction(self.tr("Remove GIF images"), self.removeGifImages) toolsMenu.addAction(self.tr("Remove all inline frames"), self.removeInlineFrames) toolsMenu.addAction(self.tr("Remove all object elements"), self.removeObjectElements) toolsMenu.addAction(self.tr("Remove all embedded elements"), self.removeEmbeddedElements) self.setCentralWidget(self.view) @Slot() def adjustLocation(self): self.locationEdit.setText(self.view.url().toString()) @Slot() def changeLocation(self): url = QUrl.fromUserInput(self.locationEdit.text()) self.view.load(url) self.view.setFocus() @Slot() def adjustTitle(self): if self.progress <= 0 or self.progress >= 100: self.setWindowTitle(self.view.title()) else: self.setWindowTitle("%s (%2d)" % (self.view.title(), self.progress)) @Slot(int) def setProgress(self, p): self.progress = p self.adjustTitle() @Slot() def finishLoading(self): self.progress = 100 self.adjustTitle() self.view.page().runJavaScript(self.jQuery) self.rotateImages(self.rotateAction.isChecked()) @Slot() def viewSource(self): self.textEdit = QTextEdit() self.textEdit.setAttribute(Qt.WA_DeleteOnClose) self.textEdit.adjustSize() self.textEdit.move(self.geometry().center() - self.textEdit.rect().center()) self.textEdit.show() self.view.page().toHtml(self.textEdit.setPlainText) @Slot() def highlightAllLinks(self): code = "qt.jQuery('a').each( function () { qt.jQuery(this).css('background-color', 'yellow') } )" self.view.page().runJavaScript(code) @Slot(bool) def rotateImages(self, invert): code = "" if invert: code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(180deg)') } )" # noqa: E501 else: code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('transition', 'transform 2s'); qt.jQuery(this).css('transform', 'rotate(0deg)') } )" # noqa: E501 self.view.page().runJavaScript(code) @Slot() def removeGifImages(self): code = "qt.jQuery('[src*=gif]').remove()" self.view.page().runJavaScript(code) @Slot() def removeInlineFrames(self): code = "qt.jQuery('iframe').remove()" self.view.page().runJavaScript(code) @Slot() def removeObjectElements(self): code = "qt.jQuery('object').remove()" self.view.page().runJavaScript(code) @Slot() def removeEmbeddedElements(self): code = "qt.jQuery('embed').remove()" self.view.page().runJavaScript(code)
def createPropertiesWidget(self, propertiesWidget): self.propertyEditor = weakref.ref(propertiesWidget) baseCategory = CollapsibleFormWidget(headName="Base") le_name = QLineEdit(self.getName()) le_name.setReadOnly(True) baseCategory.addWidget("Name", le_name) leUid = QLineEdit(str(self._rawNode.graph().name)) leUid.setReadOnly(True) baseCategory.addWidget("Owning graph", leUid) text = "{0}".format(self.packageName) if self._rawNode.lib: text += " | {0}".format(self._rawNode.lib) text += " | {0}".format(self._rawNode.__class__.__name__) leType = QLineEdit(text) leType.setReadOnly(True) baseCategory.addWidget("Type", leType) self.propertyEditor().addWidget(baseCategory) self.createInputWidgets(self.propertyEditor()) Info = CollapsibleFormWidget(headName="Info", collapsed=True) doc = QTextBrowser() doc.setOpenExternalLinks(True) doc.setHtml(self.description()) Info.addWidget(widget=doc) self.propertyEditor().addWidget(Info)
def createPropertiesWidget(self, propertiesWidget): baseCategory = CollapsibleFormWidget(headName="Base") # name le_name = QLineEdit(self.getName()) le_name.setReadOnly(True) # if self.isRenamable(): le_name.setReadOnly(False) le_name.returnPressed.connect(lambda: self.setName(le_name.text())) baseCategory.addWidget("Name", le_name) # type leType = QLineEdit(self.__class__.__name__) leType.setReadOnly(True) baseCategory.addWidget("Type", leType) # pos le_pos = QLineEdit("{0} x {1}".format(self.pos().x(), self.pos().y())) baseCategory.addWidget("Pos", le_pos) propertiesWidget.addWidget(baseCategory) appearanceCategory = CollapsibleFormWidget(headName="Appearance") pb = QPushButton("...") pb.clicked.connect(lambda: self.onChangeColor(True)) appearanceCategory.addWidget("Color", pb) propertiesWidget.addWidget(appearanceCategory) infoCategory = CollapsibleFormWidget(headName="Info") doc = QTextBrowser() doc.setOpenExternalLinks(True) doc.setHtml(self.description()) infoCategory.addWidget("", doc) propertiesWidget.addWidget(infoCategory)
def _addQLineEditBox(self, label): lineEdit = QLineEdit() lineEdit.setText(label) return lineEdit
def _build_ui(self): layout = QGridLayout() tab_widget = QTabWidget() layout.addWidget(tab_widget) structure_widget = QWidget() structure_layout = QGridLayout(structure_widget) tab_widget.addTab(structure_widget, "structure") self.structure_source = QComboBox() self.structure_source.addItems( ["AARON template", "file", "coordination complexes", "SMILES"]) structure_layout.addWidget(QLabel("structure source:"), 0, 0, 1, 1, Qt.AlignLeft | Qt.AlignVCenter) structure_layout.addWidget( self.structure_source, 0, 1, 1, 1, ) open_button = QPushButton("open") open_button.clicked.connect(self.open_template) structure_layout.addWidget( open_button, 0, 2, 1, 1, ) # SMILES options self.smiles_options = QGroupBox("SMILES options") smiles_layout = QFormLayout(self.smiles_options) structure_layout.addWidget(self.smiles_options, 1, 0, 1, 3, Qt.AlignTop | Qt.AlignHCenter) self.smiles_line = QLineEdit() smiles_layout.addRow("SMILES string:", self.smiles_line) self.smiles_options.setVisible( self.structure_source.currentText() == "SMILES") self.structure_source.currentTextChanged.connect( lambda text: self.smiles_options.setVisible(text == "SMILES")) # coordination complexes options self.coord_comp_options = QGroupBox("Coordination Complex Options") coord_layout = QFormLayout(self.coord_comp_options) structure_layout.addWidget(self.coord_comp_options, 1, 0, 1, 3, Qt.AlignTop | Qt.AlignHCenter) create_coord_items(self, coord_layout, allow_minimization=False, default_ele="Pd") self.coord_comp_options.setVisible( self.structure_source.currentText() == "coordination complexes") self.structure_source.currentTextChanged.connect( lambda text: self.coord_comp_options.setVisible( text == "coordination complexes")) # aaron template options self.aaron_options = QGroupBox("AARON template structures") aaron_layout = QFormLayout(self.aaron_options) structure_layout.addWidget(self.aaron_options, 1, 0, 1, 3, Qt.AlignTop | Qt.AlignHCenter) self.aaron_options.setVisible( self.structure_source.currentText() == "AARON template") self.structure_source.currentTextChanged.connect( lambda text: self.aaron_options.setVisible(text == "AARON template" )) # file options self.file_options = QGroupBox("single file options") file_layout = QFormLayout(self.file_options) structure_layout.addWidget(self.file_options, 1, 0, 1, 3, Qt.AlignTop | Qt.AlignHCenter) file_widget = QWidget() file_browse_layout = QGridLayout(file_widget) self.template_file = QLineEdit() file_browse_layout.addWidget(self.template_file, 0, 0, 1, 1, Qt.AlignCenter) browse_button = QPushButton("browse...") # browse_button.clicked.connect(self.browse_file_template) file_browse_layout.addWidget(browse_button, 0, 1, 1, 1, Qt.AlignCenter) file_browse_layout.setColumnStretch(0, 1) file_browse_layout.setColumnStretch(1, 0) margins = file_browse_layout.contentsMargins() file_browse_layout.setContentsMargins(margins.left(), 0, margins.right(), 0) file_layout.addRow("file:", file_widget) self.file_options.setVisible( self.structure_source.currentText() == "file") self.structure_source.currentTextChanged.connect( lambda text: self.file_options.setVisible(text == "file")) self.optimize_template = QCheckBox() self.optimize_template.setCheckState(Qt.Checked) structure_layout.addWidget( QLabel("optimize template:"), 2, 0, 1, 1, Qt.AlignLeft | Qt.AlignVCenter, ) structure_layout.addWidget( self.optimize_template, 2, 1, 1, 2, Qt.AlignLeft | Qt.AlignVCenter, ) structure_layout.setColumnStretch(0, 0) structure_layout.setColumnStretch(1, 1) structure_layout.setColumnStretch(2, 0) # structure changes changes_widget = QWidget() changes_layout = QGridLayout(changes_widget) tab_widget.addTab(changes_widget, "changes") # HPC settings hpc_widget = QWidget() hpc_layout = QGridLayout(hpc_widget) tab_widget.addTab(hpc_widget, "HPC") # theory settings theory_widget = QWidget() theory_layout = QGridLayout(theory_widget) tab_widget.addTab(theory_widget, "theory") # results results_widget = QWidget() results_layout = QGridLayout(results_widget) tab_widget.addTab(results_widget, "results") self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None)
class Client(QDialog): def __init__(self, parent: QWidget = None): super().__init__(parent) self._in = QDataStream() self.blockSize = 0 self.currentFortune = "" self.hostLineEdit = QLineEdit("fortune") self.getFortuneButton = QPushButton(self.tr("Get Fortune")) self.statusLabel = QLabel( self.tr( "This examples requires that you run the Local Fortune Server example as well." ) ) self.socket = QLocalSocket() self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) hostLabel = QLabel(self.tr("&Server name:")) hostLabel.setBuddy(self.hostLineEdit) self.statusLabel.setWordWrap(True) self.getFortuneButton.setDefault(True) quitButton = QPushButton(self.tr("Quit")) buttonBox = QDialogButtonBox() buttonBox.addButton(self.getFortuneButton, QDialogButtonBox.ActionRole) buttonBox.addButton(quitButton, QDialogButtonBox.RejectRole) self._in.setDevice(self.socket) self._in.setVersion(QDataStream.Qt_5_10) self.hostLineEdit.textChanged.connect(self.enableGetFortuneButton) self.getFortuneButton.clicked.connect(self.requestNewFortune) quitButton.clicked.connect(self.close) self.socket.readyRead.connect(self.readFortune) self.socket.errorOccurred.connect(self.displayError) mainLayout = QGridLayout(self) mainLayout.addWidget(hostLabel, 0, 0) mainLayout.addWidget(self.hostLineEdit, 0, 1) mainLayout.addWidget(self.statusLabel, 2, 0, 1, 2) mainLayout.addWidget(buttonBox, 3, 0, 1, 2) self.setWindowTitle(QGuiApplication.applicationDisplayName()) self.hostLineEdit.setFocus() @Slot() def requestNewFortune(self): self.getFortuneButton.setEnabled(False) self.blockSize = 0 self.socket.abort() self.socket.connectToServer(self.hostLineEdit.text()) @Slot() def readFortune(self): if self.blockSize == 0: # Relies on the fact that QDataStream serializes a quint32 into # sizeof(quint32) bytes if self.socket.bytesAvailable() < 4: # (int)sizeof(quint32)) return self.blockSize = self._in.readUInt32() if self.socket.bytesAvailable() < self.blockSize or self._in.atEnd(): return nextFortune = "" nextFortune = self._in.readQString() if nextFortune == self.currentFortune: QTimer.singleShot(0, self.requestNewFortune) return currentFortune = nextFortune self.statusLabel.setText(currentFortune) self.getFortuneButton.setEnabled(True) @Slot(QLocalSocket.LocalSocketError) def displayError(self, socketError): if socketError == QLocalSocket.ServerNotFoundError: QMessageBox.information( self, self.tr("Local Fortune Client"), self.tr( "The host was not found. Please make sure " "that the server is running and that the " "server name is correct." ), ) elif socketError == QLocalSocket.ConnectionRefusedError: QMessageBox.information( self, self.tr("Local Fortune Client"), self.tr( "The connection was refused by the peer. " "Make sure the fortune server is running, " "and check that the server name is correct." ), ) elif socketError == QLocalSocket.PeerClosedError: return else: QMessageBox.information( self, self.tr("Local Fortune Client"), self.tr( "The following error occurred: %s." % (self.socket.errorString()) ), ) self.getFortuneButton.setEnabled(True) @Slot() def enableGetFortuneButton(self): self.getFortuneButton.setEnabled(bool(self.hostLineEdit.ext()))
class DockTitleBar(QWidget, object): def __init__(self, dock_widget, renamable=False): super(DockTitleBar, self).__init__(dock_widget) self._renamable = renamable main_layout = layouts.HorizontalLayout(spacing=1, margins=(0, 0, 0, 1)) self.setLayout(main_layout) self._buttons_box = QGroupBox('') self._buttons_box.setObjectName('Docked') self._buttons_layout = layouts.HorizontalLayout(spacing=0, margins=(0, 0, 0, 0)) self._buttons_layout.setSpacing(1) self._buttons_layout.setMargin(2) self._buttons_box.setLayout(self._buttons_layout) main_layout.addWidget(self._buttons_box) self._title_label = QLabel(self) self._title_label.setStyleSheet('background: transparent') self._title_edit = QLineEdit(self) self._title_edit.setVisible(False) self._button_size = QSize(15, 15) self._dock_btn = QToolButton(self) self._dock_btn.setIcon(resources.icon('restore_window', theme='color')) self._dock_btn.setMaximumSize(self._button_size) self._dock_btn.setAutoRaise(True) self._close_btn = QToolButton(self) self._close_btn.setIcon(resources.icon('close_window', theme='color')) self._close_btn.setMaximumSize(self._button_size) self._close_btn.setAutoRaise(True) self._buttons_layout.addSpacing(2) self._buttons_layout.addWidget(self._title_label) self._buttons_layout.addWidget(self._title_edit) self._buttons_layout.addStretch() self._buttons_layout.addSpacing(5) self._buttons_layout.addWidget(self._dock_btn) self._buttons_layout.addWidget(self._close_btn) self._buttons_box.mouseDoubleClickEvent = self.mouseDoubleClickEvent self._buttons_box.mousePressEvent = self.mousePressEvent self._buttons_box.mouseMoveEvent = self.mouseMoveEvent self._buttons_box.mouseReleaseEvent = self.mouseReleaseEvent dock_widget.featuresChanged.connect(self._on_dock_features_changed) self._title_edit.editingFinished.connect(self._on_finish_edit) self._dock_btn.clicked.connect(self._on_dock_btn_clicked) self._close_btn.clicked.connect(self._on_close_btn_clicked) self._on_dock_features_changed(dock_widget.features()) self.set_title(dock_widget.windowTitle()) dock_widget.installEventFilter(self) dock_widget.topLevelChanged.connect(self._on_change_floating_style) @property def renamable(self): return self._renamable @renamable.setter def renamable(self, flag): self._renamable = flag def eventFilter(self, obj, event): try: if event.type() == QEvent.WindowTitleChange: self.set_title(obj.windowTitle()) return super(DockTitleBar, self).eventFilter(obj, event) except Exception as exc: event.accept() return True def mouseMoveEvent(self, event): event.ignore() def mousePressEvent(self, event): event.ignore() def mouseReleaseEvent(self, event): event.ignore() def mouseDoubleClickEvent(self, event): if event.pos().x() <= self._title_label.width() and self._renamable: self._start_edit() else: super(DockTitleBar, self).mouseDoubleClickEvent(event) def update(self, *args, **kwargs): self._on_change_floating_style(self.parent().isFloating()) super(DockTitleBar, self).update(*args, **kwargs) def set_title(self, title): self._title_label.setText(title) self._title_edit.setText(title) def add_button(self, button): button.setAutoRaise(True) button.setMaximumSize(self._button_size) self._buttons_layout.insertWidget(5, button) def _start_edit(self): self._title_label.hide() self._title_edit.show() self._title_edit.setFocus() def _finish_edit(self): self._title_edit.hide() self._title_label.show() self.parent().setWindowTitle(self._title_edit.text()) def _on_dock_features_changed(self, features): if not features & QDockWidget.DockWidgetVerticalTitleBar: self._close_btn.setVisible(features & QDockWidget.DockWidgetClosable) self._dock_btn.setVisible(features & QDockWidget.DockWidgetFloatable) else: raise ValueError('Vertical title bar is not supported!') def _on_finish_edit(self): self._finish_edit() def _on_dock_btn_clicked(self): self.parent().setFloating(not self.parent().isFloating()) def _on_close_btn_clicked(self): self.parent().toggleViewAction().setChecked(False) self.parent().close() def _on_change_floating_style(self, state): pass
class CSSEditor: """ Make sure to instanciate *after* creating the top level widgets of your QApplication """ def __init__(self, project_name): self.project_name = project_name self._app = QApplication.instance() self._css_filepath = None self.main_window = QWidget() self.main_window.setWindowFlags(Qt.Tool) self.main_window.setWindowTitle("CSS Editor - " + self.project_name) self.variables = Variables() self.variables.changed.connect(self._variables_changed) self.variables.changed.connect(self._render_and_apply) self.template = CSSTextEdit() self.template.changed.connect(self._template_changed) self.template.changed.connect(self._render_and_apply) self.save = QPushButton('Save stylesheet to') self.save.clicked.connect(self._save_stylesheet) self.save_destination = QLineEdit() self.save_destination.textChanged.connect(self._destination_changed) self.splitter = QSplitter() self.splitter.setOrientation(Qt.Vertical) self.splitter.addWidget(self.variables) self.splitter.addWidget(self.template) layout = QGridLayout(self.main_window) layout.addWidget(self.splitter, 0, 0, 1, 2) layout.addWidget(self.save, 1, 0) layout.addWidget(self.save_destination, 1, 1) self.main_window.resize(800, 600) self._project_dir = self._ensure_project_dir() self._top_level_widgets = [ widget for widget in QApplication.topLevelWidgets() if widget.windowTitle() != self.main_window.windowTitle() ] self._variables = dict() self._template = None self._stylesheet = "" self._app.aboutToQuit.connect(self._save_editor_state) self._open() self.save_destination.setText(self.css_filepath) self.main_window.show() @property def css_filepath(self): if self._css_filepath is None: return self._project_dir + self.project_name + '.css' return self._css_filepath def _ensure_project_dir(self): dir_ = os.path.expanduser('~/CSSEditor/' + self.project_name + '/') if not os.path.isdir(dir_): os.makedirs(dir_) return dir_ def _open(self): self.variables.blockSignals(True) self.template.blockSignals(True) try: with open(self._project_dir + EDITOR_STATE, 'r') as qsseditor_file: qsseditor = json.load(qsseditor_file) WindowPosition.restore(self.main_window, qsseditor['window']) self.splitter.setSizes(qsseditor['splitter']) self._css_filepath = qsseditor.get('save_destination', self.css_filepath) self.save_destination.setText(self._css_filepath) with open(self._project_dir + THEME_VARIABLES, 'r') as f_variables: self.variables.variables = json.load(f_variables) with open(self._project_dir + THEME_TEMPLATE, 'r') as f_template: self.template.set_plain_text(f_template.read()) except Exception as e: pass self.variables.blockSignals(False) self.template.blockSignals(False) self._template_changed() self._variables_changed() self._render_and_apply() def _destination_changed(self): self._css_filepath = self.save_destination.text() self._save_editor_state() def _save_editor_state(self): with open(self._project_dir + EDITOR_STATE, 'w+') as f_qsseditor: json.dump({ 'window': WindowPosition.save(self.main_window), 'splitter': self.splitter.sizes(), 'save_destination': self.css_filepath }, f_qsseditor) def _template_changed(self): template = self.template.plain_text() with open(self._project_dir + THEME_TEMPLATE, 'w+') as f_template: f_template.write(template) try: self._template = jinja2.Template(template) except TemplateSyntaxError: pass def _variables_changed(self): with open(self._project_dir + THEME_VARIABLES, 'w+') as f_variables: f_variables.write(json.dumps(self.variables.variables, indent=2)) self._variables = dict() for variable_name, variable_value in self.variables.variables.items(): if isinstance(variable_value, list) and len(variable_value) == 3: self._variables[variable_name] = 'rgb({})'.format(', '.join([str(channel) for channel in variable_value])) for variant in COLOR_VARIANTS: channels = [str(int(channel * variant * 0.01)) for channel in variable_value] self._variables['{}{:02d}'.format(variable_name, variant)] = 'rgb({})'.format(', '.join(channels)) else: self._variables[variable_name] = variable_value def _apply_style(self, style): for widget in self._top_level_widgets: widget.setStyleSheet(style) def _render_and_apply(self): self._apply_style("") if self._template is None: return self._stylesheet = self._template.render(**self._variables) self._apply_style(self._stylesheet) def _save_stylesheet(self): stylesheet = [ "/* GUI Bedos - CSS Template */", "/****************************/", "", "/* VARIABLES", json.dumps(self.variables.variables, indent=2), "/****************************/", "", "/* TEMPLATE", self.template.plain_text().replace('*/', '*|'), "/****************************/", "", "/* ACTUAL CSS */", "", self._stylesheet ] with open(self.css_filepath, 'w+') as f_stylesheet: f_stylesheet.write('\n'.join(stylesheet))
def onUpdatePropertyView(self, formLayout): # name le_name = QLineEdit(self.getName()) le_name.setReadOnly(True) if self.label().IsRenamable(): le_name.setReadOnly(False) le_name.returnPressed.connect(lambda: self.setName(le_name.text())) formLayout.addRow("Name", le_name) # uid leUid = QLineEdit(str(self.uid)) leUid.setReadOnly(True) formLayout.addRow("Uuid", leUid) # type leType = QLineEdit(self.__class__.__name__) leType.setReadOnly(True) formLayout.addRow("Type", leType) # pos le_pos = QLineEdit("{0} x {1}".format(self.pos().x(), self.pos().y())) formLayout.addRow("Pos", le_pos) pb = QPushButton("...") pb.clicked.connect(self.onChangeColor) formLayout.addRow("Color", pb) doc_lb = QLabel() doc_lb.setStyleSheet("background-color: black;") doc_lb.setText("Description") formLayout.addRow("", doc_lb) doc = QTextBrowser() doc.setOpenExternalLinks(True) doc.setHtml(self.description()) formLayout.addRow("", doc)
def ui(self): super(BaseFileFolderDialog, self).ui() from tpDcc.libs.qt.widgets import directory self.places = dict() self.grid = layouts.GridLayout() sub_grid = layouts.GridLayout() self.grid.addWidget(QLabel('Path:'), 0, 0, Qt.AlignRight) self.path_edit = QLineEdit(self) self.path_edit.setReadOnly(True) self.filter_box = QComboBox(self) self.file_edit = QLineEdit(self) self.view = directory.FileListWidget(self) self.view.setWrapping(True) self.view.setFocusPolicy(Qt.StrongFocus) self.open_button = QPushButton('Select', self) self.cancel_button = QPushButton('Cancel', self) size = QSize(32, 24) self.up_button = QPushButton('Up') self.up_button.setToolTip('Go up') self.up_button.setMinimumSize(size) self.up_button.setMaximumSize(size) size = QSize(56, 24) self.refresh_button = QPushButton('Reload') self.refresh_button.setToolTip('Reload file list') self.refresh_button.setMinimumSize(size) self.refresh_button.setMaximumSize(size) self.show_hidden = QCheckBox('Hidden') self.show_hidden.setChecked(False) self.show_hidden.setToolTip('Toggle show hidden files') sub_grid.addWidget(self.up_button, 0, 1) sub_grid.addWidget(self.path_edit, 0, 2) sub_grid.addWidget(self.refresh_button, 0, 3) sub_grid.addWidget(self.show_hidden, 0, 4) self.grid.addLayout(sub_grid, 0, 1) self.grid.addWidget(self.get_drives_widget(), 1, 0) self.grid.addWidget(self.view, 1, 1) self.grid.addWidget(QLabel('File name:'), 7, 0, Qt.AlignRight) self.grid.addWidget(self.file_edit, 7, 1) self.filter_label = QLabel('Filter:') self.grid.addWidget(self.filter_label, 8, 0, Qt.AlignRight) self.grid.addWidget(self.filter_box, 8, 1) hbox = layouts.GridLayout() hbox.addWidget(self.open_button, 0, 0, Qt.AlignRight) hbox.addWidget(self.cancel_button, 0, 1, Qt.AlignRight) self.grid.addLayout(hbox, 9, 1, Qt.AlignRight) self.main_layout.addLayout(self.grid) self.setGeometry(200, 100, 600, 400) self.open_button.clicked.connect(self.accept) self.cancel_button.clicked.connect(self.reject) self.up_button.clicked.connect(self.go_up) self.refresh_button.clicked.connect(self.update_view) self.show_hidden.stateChanged.connect(self.update_view) self.view.directory_activated.connect( self.activate_directory_from_view) self.view.file_activated.connect(self.activate_file_from_view) self.view.file_selected.connect(self.select_file_item) self.view.folder_selected.connect(self.select_folder_item) self.view.up_requested.connect(self.go_up) self.view.update_requested.connect(self.update_view)
def createPropertiesWidget(self, propertiesWidget): baseCategory = CollapsibleFormWidget(headName="Base") # name le_name = QLineEdit(self._rawVariable.name) le_name.returnPressed.connect(lambda: self.setName(le_name.text())) baseCategory.addWidget("Name", le_name) # data type if self._rawVariable.structure == StructureType.Dict: dictObject = self._rawVariable.value keyTypeSelector = EnumComboBox(values=getHashableDataTypes()) valueTypeSelector = EnumComboBox([ pin.__name__ for pin in getAllPinClasses() if pin.IsValuePin() if pin.__name__ != "AnyPin" ]) keyTypeSelector.setEditable(False) valueTypeSelector.setEditable(False) keyTypeSelector.setCurrentIndex( keyTypeSelector.findText(dictObject.keyType)) valueTypeSelector.setCurrentIndex( valueTypeSelector.findText(dictObject.valueType)) keyTypeSelector.changeCallback.connect(self.onDictKeyTypeChanged) valueTypeSelector.changeCallback.connect( self.onDictValueTypeChanged) baseCategory.addWidget("Key type", keyTypeSelector) baseCategory.addWidget("Value type", valueTypeSelector) else: cbTypes = EnumComboBox([ pin.__name__ for pin in getAllPinClasses() if pin.IsValuePin() if pin.__name__ != "AnyPin" ]) cbTypes.setCurrentIndex(cbTypes.findText(self.dataType)) cbTypes.changeCallback.connect(self.setDataType) cbTypes.setEditable(False) baseCategory.addWidget("Type", cbTypes) propertiesWidget.addWidget(baseCategory) # structure type cbStructure = EnumComboBox( [i.name for i in (StructureType.Single, StructureType.Array)]) cbStructure.setEditable(False) cbStructure.setCurrentIndex( cbStructure.findText(self._rawVariable.structure.name)) cbStructure.changeCallback.connect(self.onStructureChanged) propertiesWidget.addWidget(baseCategory) baseCategory.addWidget("Structure", cbStructure) valueCategory = CollapsibleFormWidget(headName="Value") # current value if self._rawVariable.structure == StructureType.Single: if not type(self._rawVariable.value) in {list, set, dict, tuple}: def valSetter(x): self._rawVariable.value = x w = createInputWidget( self._rawVariable.dataType, valSetter, getPinDefaultValueByType(self._rawVariable.dataType)) if w: w.setWidgetValue(self._rawVariable.value) w.setObjectName(self._rawVariable.name) valueCategory.addWidget(self._rawVariable.name, w) # access level cb = QComboBox() cb.addItem('public', 0) cb.addItem('private', 1) cb.addItem('protected', 2) def accessLevelChanged(x): self._rawVariable.accessLevel = AccessLevel[x] EditorHistory().saveState("Change variable access level", modify=True) cb.currentTextChanged.connect(accessLevelChanged) cb.setCurrentIndex(self._rawVariable.accessLevel) valueCategory.addWidget('Access level', cb) propertiesWidget.addWidget(valueCategory)
def __init__( self, parent=None, singleSelect=False, maxDenticity=None, include_substituents=False, ): super().__init__(parent) self._include_substituents = include_substituents layout = QGridLayout(self) self.table = QTableWidget() self.table.setColumnCount(3) self.table.setHorizontalHeaderLabels( ['name', 'denticity', 'coordinating elements']) self.add_ligands(maxDenticity) for i in range(0, 3): self.table.resizeColumnToContents(i) self.table.horizontalHeader().setStretchLastSection(False) self.table.horizontalHeader().setSectionResizeMode( 0, QHeaderView.Fixed) self.table.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Fixed) self.table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Stretch) self.table.setSortingEnabled(True) self.table.setSelectionBehavior(QTableWidget.SelectRows) if singleSelect: self.table.setSelectionMode(QTableWidget.SingleSelection) self.table.setEditTriggers(QTableWidget.NoEditTriggers) self.filterEdit = QLineEdit() self.filterEdit.textChanged.connect(self.apply_filter) self.filterEdit.setClearButtonEnabled(True) self.filter_columns = QComboBox() self.filter_columns.addItem("name") self.filter_columns.addItem("denticity") self.filter_columns.addItem("coordinating elements") self.filter_columns.currentTextChanged.connect( self.change_filter_method) self.name_regex_option = QComboBox() self.name_regex_option.addItem("case-insensitive") self.name_regex_option.addItem("case-sensitive") self.name_regex_option.currentTextChanged.connect(self.apply_filter) self.name_regex_option.setVisible( self.filter_columns.currentText() == "name") self.coordinating_elements_method = QComboBox() self.coordinating_elements_method.addItem("exactly") self.coordinating_elements_method.addItem("at least") self.coordinating_elements_method.currentTextChanged.connect( self.apply_filter) self.coordinating_elements_method.setVisible( self.filter_columns.currentText() == "coordinating elements") layout.addWidget(self.table, 0, 0, 1, 4) layout.addWidget(QLabel("filter based on"), 1, 0) layout.addWidget(self.filter_columns, 1, 1) layout.addWidget(self.coordinating_elements_method, 1, 2) layout.addWidget(self.name_regex_option, 1, 2) layout.addWidget(self.filterEdit, 1, 3) self.change_filter_method("name")
class _SubstituentSelector(ToolInstance): def __init__(self, session, name): super().__init__(session, name) self.tool_window = MainToolWindow(self) self._build_ui() def _build_ui(self): layout = QFormLayout() self.substituent_table = SubstituentTable(singleSelect=True) layout.addRow(self.substituent_table) self.new_residue = QCheckBox() self.new_residue.setCheckState( Qt.Checked if SubstituteMouseMode.newRes else Qt.Unchecked) layout.addRow("new residue:", self.new_residue) self.res_name = QLineEdit() self.res_name.setPlaceholderText("leave blank to keep current") layout.addRow("set residue name:", self.res_name) self.distance_names = QCheckBox() self.distance_names.setCheckState( Qt.Checked if SubstituteMouseMode.useRemoteness else Qt.Unchecked) layout.addRow("distance atom names:", self.distance_names) self.keep_open = QCheckBox() layout.addRow("keep list open:", self.keep_open) do_it = QPushButton("set substituent") do_it.clicked.connect(self.set_sub) layout.addRow(do_it) self.keep_open.stateChanged.connect( lambda state: do_it.setVisible(state != Qt.Checked)) self.keep_open.stateChanged.connect(self.sub_changed) self.substituent_table.table.itemSelectionChanged.connect( self.sub_changed) self.new_residue.stateChanged.connect(self.sub_changed) self.res_name.textChanged.connect(self.sub_changed) self.distance_names.stateChanged.connect(self.sub_changed) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None) def sub_changed(self): if self.keep_open.checkState() == Qt.Checked: self.set_sub() def set_sub(self): sub_names = [] for row in self.substituent_table.table.selectionModel().selectedRows( ): if self.substituent_table.table.isRowHidden(row.row()): continue sub_names.append(row.data()) if sub_names: SubstituteMouseMode.substituent = sub_names[0] SubstituteMouseMode.newRes = self.new_residue.checkState( ) == Qt.Checked SubstituteMouseMode.useRemoteness = self.distance_names.checkState( ) == Qt.Checked sub_name = self.res_name.text() SubstituteMouseMode.resName = sub_name if self.keep_open.checkState() != Qt.Checked: self.delete() def close(self): sub_names = [] for row in self.substituent_table.table.selectionModel().selectedRows( ): if self.substituent_table.table.isRowHidden(row.row()): continue sub_names.append(row.data()) if sub_names: SubstituteMouseMode.substituent = sub_names[0] SubstituteMouseMode.newRes = self.new_residue.checkState( ) == Qt.Checked SubstituteMouseMode.useRemoteness = self.distance_names.checkState( ) == Qt.Checked sub_name = self.res_name.text() SubstituteMouseMode.resName = sub_name super().close()