예제 #1
0
파일: partedit.py 프로젝트: wdas/partio
 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())
예제 #2
0
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))
예제 #3
0
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)
예제 #4
0
    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)
예제 #5
0
    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)
예제 #6
0
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)
예제 #7
0
 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))
예제 #8
0
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()
예제 #9
0
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()
예제 #10
0
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'])
예제 #11
0
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)
예제 #12
0
파일: libadd.py 프로젝트: QChASM/SEQCROW
    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)
예제 #13
0
파일: libadd.py 프로젝트: QChASM/SEQCROW
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)
예제 #14
0
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)
예제 #15
0
    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)
예제 #16
0
파일: partedit.py 프로젝트: wdas/partio
    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)
예제 #17
0
 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])
예제 #18
0
    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)
예제 #19
0
    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)
예제 #20
0
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)
예제 #21
0
    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)
예제 #22
0
    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)
예제 #23
0
	def _addQLineEditBox(self, label):
		lineEdit = QLineEdit()
		lineEdit.setText(label)
		return lineEdit
예제 #24
0
    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)
예제 #25
0
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()))
예제 #26
0
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
예제 #27
0
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))
예제 #28
0
    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)
예제 #29
0
    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)
예제 #31
0
    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")
예제 #32
0
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()