Пример #1
0
class ClosableDialog(QDialog):

    def __init__(self, title, widget, parent=None):
        QDialog.__init__(self, parent)

        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)

        layout = QVBoxLayout()
        layout.setSizeConstraint(QLayout.SetFixedSize) # not resizable!!!
        layout.addWidget(widget)

        self.__button_layout = QHBoxLayout()
        self.close_button = QPushButton("Close")
        self.close_button.setObjectName("CLOSE")
        self.close_button.clicked.connect(self.accept)
        self.__button_layout.addStretch()
        self.__button_layout.addWidget(self.close_button)

        layout.addStretch()
        layout.addLayout(self.__button_layout)

        self.setLayout(layout)

    def disableCloseButton(self):
        self.close_button.setEnabled(False)

    def enableCloseButton(self):
        self.close_button.setEnabled(True)

    def keyPressEvent(self, q_key_event):
        if not self.close_button.isEnabled() and q_key_event.key() == Qt.Key_Escape:
            pass
        else:
            QDialog.keyPressEvent(self, q_key_event)

    def addButton(self, caption, listner):
        button = QPushButton(caption)
        button.setObjectName(str(caption).capitalize())
        self.__button_layout.insertWidget(1,button)
        button.clicked.connect(listner)

    def toggleButton(self, caption, enabled):
        button = self.findChild(QPushButton,str(caption).capitalize())
        if button is not None:
            button.setEnabled(enabled)
Пример #2
0
class WorkflowDialog(QDialog):

    closeButtonPressed = Signal()

    def __init__(self, title, widget, parent=None):
        QDialog.__init__(self, parent)

        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)

        layout = QVBoxLayout()
        layout.setSizeConstraint(QLayout.SetFixedSize)  # not resizable!!!
        layout.addWidget(widget)

        button_layout = QHBoxLayout()
        self.close_button = QPushButton("Close")
        self.close_button.clicked.connect(self.closeButtonPressed.emit)
        button_layout.addStretch()
        button_layout.addWidget(self.close_button)

        layout.addStretch()
        layout.addLayout(button_layout)

        self.setLayout(layout)

    def disableCloseButton(self):
        self.close_button.setEnabled(False)

    def enableCloseButton(self):
        self.close_button.setEnabled(True)

    def keyPressEvent(self, q_key_event):
        if not self.close_button.isEnabled() and q_key_event.key(
        ) == Qt.Key_Escape:
            pass
        else:
            QDialog.keyPressEvent(self, q_key_event)
Пример #3
0
class DlgGitHubLogin(QDialog):
    """Dialog to submit error reports to Github."""
    def __init__(self, parent, username):
        super(DlgGitHubLogin, self).__init__(parent)

        title = _("Sign in to Github")
        self.resize(366, 248)
        self.setWindowTitle(title)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)

        # Header
        html = ('<html><head/><body><p align="center"><img src="{mark}"/></p>'
                '<p align="center">{title}</p></body></html>')
        mark = GH_MARK_NORMAL
        if self.palette().base().color().lightness() < 128:
            mark = GH_MARK_LIGHT
        lbl_html = QLabel(html.format(mark=mark, title=title))

        # Tabs
        tabs = QTabWidget()

        # Basic form layout
        basic_form_layout = QFormLayout()
        basic_form_layout.setContentsMargins(-1, 0, -1, -1)

        lbl_user = QLabel(_("Username:"******"Password: "******"Basic authentication"))

        # Token form layout
        token_form_layout = QFormLayout()
        token_form_layout.setContentsMargins(-1, 0, -1, -1)

        lbl_token = QLabel("Token: ")
        token_form_layout.setWidget(1, QFormLayout.LabelRole, lbl_token)
        self.le_token = QLineEdit()
        self.le_token.setEchoMode(QLineEdit.Password)
        self.le_token.textChanged.connect(self.update_btn_state)
        token_form_layout.setWidget(1, QFormLayout.FieldRole, self.le_token)

        # Token auth tab
        token_auth = QWidget()
        token_layout = QVBoxLayout()
        token_layout.addLayout(token_form_layout)
        token_layout.addStretch(1)
        token_auth.setLayout(token_layout)
        tabs.addTab(token_auth, _("Token authentication"))

        # Sign in button
        self.bt_sign_in = QPushButton(_("Sign in"))
        self.bt_sign_in.clicked.connect(self.accept)
        self.bt_sign_in.setDisabled(True)

        # Main layout
        layout = QVBoxLayout()
        layout.addWidget(lbl_html)
        layout.addWidget(tabs)
        layout.addWidget(self.bt_sign_in)
        self.setLayout(layout)

        # Final adjustments
        if username:
            self.le_user.setText(username)
            self.le_password.setFocus()
        else:
            self.le_user.setFocus()

        self.setFixedSize(self.width(), self.height())
        self.le_password.installEventFilter(self)
        self.le_user.installEventFilter(self)

    def eventFilter(self, obj, event):
        interesting_objects = [self.le_password, self.le_user]
        if obj in interesting_objects and event.type() == QEvent.KeyPress:
            if (event.key() == Qt.Key_Return
                    and event.modifiers() & Qt.ControlModifier
                    and self.bt_sign_in.isEnabled()):
                self.accept()
                return True
        return False

    def update_btn_state(self):
        user = to_text_string(self.le_user.text()).strip() != ''
        password = to_text_string(self.le_password.text()).strip() != ''
        token = to_text_string(self.le_token.text()).strip() != ''
        enable = (user and password) or token
        self.bt_sign_in.setEnabled(enable)

    @classmethod
    def login(cls, parent, username):
        dlg = DlgGitHubLogin(parent, username)
        if dlg.exec_() == dlg.Accepted:
            user = dlg.le_user.text()
            password = dlg.le_password.text()
            token = dlg.le_token.text()
            if token != '':
                return (token, )
            else:
                return user, password
        return None, None
Пример #4
0
class DlgGitHubLogin(QDialog):
    """Dialog to submit error reports to Github."""

    def __init__(self, parent, username, password, token, remember=False,
                 remember_token=False):
        QDialog.__init__(self, parent)

        title = _("Sign in to Github")
        self.resize(415, 375)
        self.setWindowTitle(title)
        self.setWindowFlags(
            self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

        # Header
        html = ('<html><head/><body><p align="center">'
                '{title}</p></body></html>')
        lbl_html = QLabel(html.format(title=title))
        lbl_html.setStyleSheet('font-size: 16px;')

        # Tabs
        self.tabs = QTabWidget()

        # Basic form layout
        basic_form_layout = QFormLayout()
        basic_form_layout.setContentsMargins(-1, 0, -1, -1)

        basic_lbl_msg = QLabel(_("For regular users, i.e. users <b>without</b>"
                                 " two-factor authentication enabled"))
        basic_lbl_msg.setWordWrap(True)
        basic_lbl_msg.setAlignment(Qt.AlignJustify)

        lbl_user = QLabel(_("Username:"******"", QWidget())

        lbl_password = QLabel(_("Password: "******"Remember me"))
            self.cb_remember.setToolTip(_("Spyder will save your credentials "
                                          "safely"))
            self.cb_remember.setChecked(remember)
            basic_form_layout.setWidget(4, QFormLayout.FieldRole,
                                        self.cb_remember)

        # Basic auth tab
        basic_auth = QWidget()
        basic_layout = QVBoxLayout()
        basic_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        basic_layout.addWidget(basic_lbl_msg)
        basic_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        basic_layout.addLayout(basic_form_layout)
        basic_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        basic_auth.setLayout(basic_layout)
        self.tabs.addTab(basic_auth, _("Password Only"))

        # Token form layout
        token_form_layout = QFormLayout()
        token_form_layout.setContentsMargins(-1, 0, -1, -1)

        token_lbl_msg = QLabel(_("For users <b>with</b> two-factor "
                                 "authentication enabled, or who prefer a "
                                 "per-app token authentication.<br><br>"
                                 "You can go <b><a href=\"{}\">here</a></b> "
                                 "and click \"Generate token\" at the bottom "
                                 "to create a new token to use for this, with "
                                 "the appropriate permissions.").format(
                                                                    TOKEN_URL))
        token_lbl_msg.setOpenExternalLinks(True)
        token_lbl_msg.setWordWrap(True)
        token_lbl_msg.setAlignment(Qt.AlignJustify)

        lbl_token = QLabel("Token: ")
        token_form_layout.setWidget(1, QFormLayout.LabelRole, lbl_token)
        self.le_token = QLineEdit()
        self.le_token.setEchoMode(QLineEdit.Password)
        self.le_token.textChanged.connect(self.update_btn_state)
        token_form_layout.setWidget(1, QFormLayout.FieldRole, self.le_token)

        self.cb_remember_token = None
        # Same validation as with cb_remember
        if self.is_keyring_available() and valid_py_os:
            self.cb_remember_token = QCheckBox(_("Remember token"))
            self.cb_remember_token.setToolTip(_("Spyder will save your "
                                                "token safely"))
            self.cb_remember_token.setChecked(remember_token)
            token_form_layout.setWidget(3, QFormLayout.FieldRole,
                                        self.cb_remember_token)

        # Token auth tab
        token_auth = QWidget()
        token_layout = QVBoxLayout()
        token_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        token_layout.addWidget(token_lbl_msg)
        token_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        token_layout.addLayout(token_form_layout)
        token_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        token_auth.setLayout(token_layout)
        self.tabs.addTab(token_auth, _("Access Token"))

        # Sign in button
        self.bt_sign_in = QPushButton(_("Sign in"))
        self.bt_sign_in.clicked.connect(self.accept)
        self.bt_sign_in.setDisabled(True)

        # Main layout
        layout = QVBoxLayout()
        layout.addWidget(lbl_html)
        layout.addWidget(self.tabs)
        layout.addWidget(self.bt_sign_in)
        self.setLayout(layout)

        # Final adjustments
        if username and password:
            self.le_user.setText(username)
            self.le_password.setText(password)
            self.bt_sign_in.setFocus()
        elif username:
            self.le_user.setText(username)
            self.le_password.setFocus()
        elif token:
            self.le_token.setText(token)
        else:
            self.le_user.setFocus()

        self.setFixedSize(self.width(), self.height())
        self.le_password.installEventFilter(self)
        self.le_user.installEventFilter(self)
        self.tabs.currentChanged.connect(self.update_btn_state)

    def eventFilter(self, obj, event):
        interesting_objects = [self.le_password, self.le_user]
        if obj in interesting_objects and event.type() == QEvent.KeyPress:
            if (event.key() == Qt.Key_Return and
                    event.modifiers() & Qt.ControlModifier and
                    self.bt_sign_in.isEnabled()):
                self.accept()
                return True
        return False

    def update_btn_state(self):
        user = to_text_string(self.le_user.text()).strip() != ''
        password = to_text_string(self.le_password.text()).strip() != ''
        token = to_text_string(self.le_token.text()).strip() != ''
        enable = ((user and password and
                  self.tabs.currentIndex() == 0) or
                  (token and self.tabs.currentIndex() == 1))
        self.bt_sign_in.setEnabled(enable)

    def is_keyring_available(self):
        """Check if keyring is available for password storage."""
        try:
            import keyring  # analysis:ignore
            return True
        except Exception:
            return False

    @classmethod
    def login(cls, parent, username, password, token,
              remember, remember_token):
        dlg = DlgGitHubLogin(parent, username, password, token, remember,
                             remember_token)
        if dlg.exec_() == dlg.Accepted:
            user = dlg.le_user.text()
            password = dlg.le_password.text()
            token = dlg.le_token.text()
            if dlg.cb_remember:
                remember = dlg.cb_remember.isChecked()
            else:
                remember = False
            if dlg.cb_remember_token:
                remember_token = dlg.cb_remember_token.isChecked()
            else:
                remember_token = False

            credentials = dict(username=user,
                               password=password,
                               token=token,
                               remember=remember,
                               remember_token=remember_token)
            return credentials

        return dict(username=None,
                    password=None,
                    token=None,
                    remember=False,
                    remember_token=False)
Пример #5
0
class DlgGitHubLogin(QDialog):
    """Dialog to submit error reports to Github."""
    def __init__(self,
                 parent,
                 username,
                 password,
                 token,
                 remember=False,
                 remember_token=False):
        QDialog.__init__(self, parent)

        title = _("Sign in to Github")
        self.resize(415, 375)
        self.setWindowTitle(title)
        self.setWindowFlags(self.windowFlags()
                            & ~Qt.WindowContextHelpButtonHint)

        # Header
        html = ('<html><head/><body><p align="center">'
                '{title}</p></body></html>')
        lbl_html = QLabel(html.format(title=title))
        lbl_html.setStyleSheet('font-size: 16px;')

        # Tabs
        self.tabs = QTabWidget()

        # Basic form layout
        basic_form_layout = QFormLayout()
        basic_form_layout.setContentsMargins(-1, 0, -1, -1)

        basic_lbl_msg = QLabel(
            _("For regular users, i.e. users <b>without</b>"
              " two-factor authentication enabled"))
        basic_lbl_msg.setWordWrap(True)
        basic_lbl_msg.setAlignment(Qt.AlignJustify)

        lbl_user = QLabel(_("Username:"******"", QWidget())

        lbl_password = QLabel(_("Password: "******"Remember me"))
            self.cb_remember.setToolTip(
                _("Spyder will save your credentials "
                  "safely"))
            self.cb_remember.setChecked(remember)
            basic_form_layout.setWidget(4, QFormLayout.FieldRole,
                                        self.cb_remember)

        # Basic auth tab
        basic_auth = QWidget()
        basic_layout = QVBoxLayout()
        basic_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        basic_layout.addWidget(basic_lbl_msg)
        basic_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        basic_layout.addLayout(basic_form_layout)
        basic_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        basic_auth.setLayout(basic_layout)
        self.tabs.addTab(basic_auth, _("Password Only"))

        # Token form layout
        token_form_layout = QFormLayout()
        token_form_layout.setContentsMargins(-1, 0, -1, -1)

        token_lbl_msg = QLabel(
            _("For users <b>with</b> two-factor "
              "authentication enabled, or who prefer a "
              "per-app token authentication.<br><br>"
              "You can go <b><a href=\"{}\">here</a></b> "
              "and click \"Generate token\" at the bottom "
              "to create a new token to use for this, with "
              "the appropriate permissions.").format(TOKEN_URL))
        token_lbl_msg.setOpenExternalLinks(True)
        token_lbl_msg.setWordWrap(True)
        token_lbl_msg.setAlignment(Qt.AlignJustify)

        lbl_token = QLabel("Token: ")
        token_form_layout.setWidget(1, QFormLayout.LabelRole, lbl_token)
        self.le_token = QLineEdit()
        self.le_token.setEchoMode(QLineEdit.Password)
        self.le_token.textChanged.connect(self.update_btn_state)
        token_form_layout.setWidget(1, QFormLayout.FieldRole, self.le_token)

        self.cb_remember_token = None
        # Same validation as with cb_remember
        if self.is_keyring_available() and valid_py_os:
            self.cb_remember_token = QCheckBox(_("Remember token"))
            self.cb_remember_token.setToolTip(
                _("Spyder will save your "
                  "token safely"))
            self.cb_remember_token.setChecked(remember_token)
            token_form_layout.setWidget(3, QFormLayout.FieldRole,
                                        self.cb_remember_token)

        # Token auth tab
        token_auth = QWidget()
        token_layout = QVBoxLayout()
        token_layout.addSpacerItem(QSpacerItem(QSpacerItem(0, 8)))
        token_layout.addWidget(token_lbl_msg)
        token_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        token_layout.addLayout(token_form_layout)
        token_layout.addSpacerItem(
            QSpacerItem(QSpacerItem(0, 50, vPolicy=QSizePolicy.Expanding)))
        token_auth.setLayout(token_layout)
        self.tabs.addTab(token_auth, _("Access Token"))

        # Sign in button
        self.bt_sign_in = QPushButton(_("Sign in"))
        self.bt_sign_in.clicked.connect(self.accept)
        self.bt_sign_in.setDisabled(True)

        # Main layout
        layout = QVBoxLayout()
        layout.addWidget(lbl_html)
        layout.addWidget(self.tabs)
        layout.addWidget(self.bt_sign_in)
        self.setLayout(layout)

        # Final adjustments
        if username and password:
            self.le_user.setText(username)
            self.le_password.setText(password)
            self.bt_sign_in.setFocus()
        elif username:
            self.le_user.setText(username)
            self.le_password.setFocus()
        elif token:
            self.le_token.setText(token)
        else:
            self.le_user.setFocus()

        self.setFixedSize(self.width(), self.height())
        self.le_password.installEventFilter(self)
        self.le_user.installEventFilter(self)
        self.tabs.currentChanged.connect(self.update_btn_state)

    def eventFilter(self, obj, event):
        interesting_objects = [self.le_password, self.le_user]
        if obj in interesting_objects and event.type() == QEvent.KeyPress:
            if (event.key() == Qt.Key_Return
                    and event.modifiers() & Qt.ControlModifier
                    and self.bt_sign_in.isEnabled()):
                self.accept()
                return True
        return False

    def update_btn_state(self):
        user = to_text_string(self.le_user.text()).strip() != ''
        password = to_text_string(self.le_password.text()).strip() != ''
        token = to_text_string(self.le_token.text()).strip() != ''
        enable = ((user and password and self.tabs.currentIndex() == 0)
                  or (token and self.tabs.currentIndex() == 1))
        self.bt_sign_in.setEnabled(enable)

    def is_keyring_available(self):
        """Check if keyring is available for password storage."""
        try:
            import keyring  # analysis:ignore
            return True
        except Exception:
            return False

    @classmethod
    def login(cls, parent, username, password, token, remember,
              remember_token):
        dlg = DlgGitHubLogin(parent, username, password, token, remember,
                             remember_token)
        if dlg.exec_() == dlg.Accepted:
            user = dlg.le_user.text()
            password = dlg.le_password.text()
            token = dlg.le_token.text()
            if dlg.cb_remember:
                remember = dlg.cb_remember.isChecked()
            else:
                remember = False
            if dlg.cb_remember_token:
                remember_token = dlg.cb_remember_token.isChecked()
            else:
                remember_token = False

            credentials = dict(username=user,
                               password=password,
                               token=token,
                               remember=remember,
                               remember_token=remember_token)
            return credentials

        return dict(username=None,
                    password=None,
                    token=None,
                    remember=False,
                    remember_token=False)
Пример #6
0
class MultipleFileWidget(QWidget):
    _add_state = Signal(object, bool)

    def __init__(self, settings: BaseSettings, load_dict: Dict[str, LoadBase], compare_in_context_menu=False):
        super().__init__()
        self.settings = settings
        self.state_dict: Dict[str, Dict[str, ProjectInfoBase]] = defaultdict(dict)
        self.state_dict_count = Counter()
        self.file_list = []
        self.load_register = load_dict
        self.file_view = CustomTreeWidget(compare_in_context_menu)
        self.file_view.header().close()
        self.save_state_btn = QPushButton("Save state")
        self.save_state_btn.setStyleSheet("QPushButton{font-weight: bold;}")
        self.load_files_btn = QPushButton("Load Files")
        self.forget_btn = QPushButton("Forget")

        self.save_state_btn.clicked.connect(self.save_state)
        self.forget_btn.clicked.connect(self.forget)
        self.load_files_btn.clicked.connect(self.load_files)
        self.file_view.itemDoubleClicked.connect(self.load_state)
        self.file_view.context_load.connect(self.load_state)
        self.last_point = None

        self.custom_names_chk = QCheckBox("Custom names")

        layout = QGridLayout()
        layout.addWidget(self.file_view, 0, 0, 1, 2)
        layout.addWidget(self.save_state_btn, 1, 0, 1, 2)
        layout.addWidget(self.load_files_btn, 2, 0)
        layout.addWidget(self.forget_btn, 2, 1)
        layout.addWidget(self.custom_names_chk, 3, 0, 1, 2)

        self.setLayout(layout)
        self.setMouseTracking(True)
        self.file_view.setMouseTracking(True)
        self.file_view.context_load.connect(self.load_state)
        self.file_view.context_compare.connect(self.load_compare)
        self.file_view.context_forget.connect(self.forget_action)
        self.error_list = []

        self._add_state.connect(self.save_state_action)

    def execute_load_files(self, load_data: LoadProperty, range_changed, step_changed):
        range_changed(0, len(load_data.load_location))
        for i, el in enumerate(load_data.load_location, 1):
            load_list = [el]
            while load_data.load_class.number_of_files() > len(load_list):
                load_list.append(load_data.load_class.get_next_file(load_list))
                if not os.path.exists(load_list[-1]):
                    self.error_list.append(el)
                    step_changed(i)
                    continue
            state: ProjectInfoBase = load_data.load_class.load(load_list)
            self._add_state.emit(state, False)
            step_changed(i)

    def load_files(self):
        def exception_hook(exception):
            from qtpy.QtCore import QMetaObject

            instance = QApplication.instance()
            if isinstance(exception, MemoryError):
                instance.warning = "Open error", f"Not enough memory to read this image: {exception}"
                QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection)
            elif isinstance(exception, IOError):
                instance.warning = "Open error", f"Some problem with reading from disc: {exception}"
                QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection)
            elif isinstance(exception, KeyError):
                instance.warning = "Open error", f"Some problem project file: {exception}"
                QMetaObject.invokeMethod(instance, "show_warning", Qt.QueuedConnection)
                print(exception, file=sys.stderr)
            else:
                raise exception

        dial = MultipleLoadDialog(self.load_register, self.settings.get_path_history())
        dial.setDirectory(self.settings.get("io.multiple_open_directory", str(Path.home())))
        dial.selectNameFilter(self.settings.get("io.multiple_open_filter", next(iter(self.load_register.keys()))))
        self.error_list = []
        if dial.exec():
            result = dial.get_result()
            load_dir = os.path.dirname(result.load_location[0])
            self.settings.set("io.multiple_open_directory", load_dir)
            self.settings.add_path_history(load_dir)
            self.settings.set("io.multiple_open_filter", result.selected_filter)

            dial_fun = ExecuteFunctionDialog(self.execute_load_files, [result], exception_hook=exception_hook)
            dial_fun.exec()
            if self.error_list:
                errors_message = QMessageBox()
                errors_message.setText("There are errors during load files")
                errors_message.setInformativeText("During load files cannot found some of files on disc")
                errors_message.setStandardButtons(QMessageBox.Ok)
                text = "\n".join(["File: " + x[0] + "\n" + str(x[1]) for x in self.error_list])
                errors_message.setDetailedText(text)
                errors_message.exec()

    def load_state(self, item, _column=1):
        if item.parent() is None:
            return
        file_name = self.file_list[self.file_view.indexOfTopLevelItem(item.parent())]
        state_name = item.text(0)
        project_info = self.state_dict[file_name][state_name]
        try:
            self.parent().parent().parent().set_data(project_info)
        except AttributeError:
            self.settings.set_project_info(project_info)

    def load_compare(self, item):
        if item.parent() is None:
            return
        file_name = self.file_list[self.file_view.indexOfTopLevelItem(item.parent())]
        if self.settings.image.file_path != file_name:
            QMessageBox.information(self, "Wrong file", "Please select same file as main")
            return
        state_name = item.text(0)
        project_info = self.state_dict[file_name][state_name]
        if hasattr(self.settings, "set_segmentation_to_compare"):
            self.settings.set_segmentation_to_compare(project_info.segmentation_info)

    def save_state(self):
        state: ProjectInfoBase = self.settings.get_project_info()
        custom_name = self.custom_names_chk.isChecked()
        self.save_state_action(state, custom_name)

    def save_state_action(self, state: ProjectInfoBase, custom_name):
        # TODO left elipsis
        # state: ProjectInfoBase = self.get_state()
        normed_file_path = os.path.normpath(state.file_path)
        sub_dict = self.state_dict[normed_file_path]
        name = f"state {self.state_dict_count[normed_file_path]+1}"
        if custom_name:
            name, ok = QInputDialog.getText(self, "Save name", "Save name:", text=name)
            if not ok:
                return
            while name in sub_dict or name in ["raw image", "image with mask"]:
                name, ok = QInputDialog.getText(self, "Save name", "Save name (previous in use):", text=name)
                if not ok:
                    return
        try:
            index = self.file_list.index(os.path.normpath(normed_file_path))
            item = self.file_view.topLevelItem(index)
        except ValueError:
            metric = QFontMetrics(self.file_view.font())
            width = self.file_view.width() - 45
            clipped_text = metric.elidedText(normed_file_path, Qt.ElideLeft, width)
            item = QTreeWidgetItem(self.file_view, [clipped_text])
            item.setToolTip(0, normed_file_path)
            self.file_list.append(normed_file_path)
            QTreeWidgetItem(item, ["raw image"])
            sub_dict["raw image"] = state.get_raw_copy()
            if state.is_masked():
                QTreeWidgetItem(item, ["image with mask"])
                sub_dict["image with mask"] = state.get_raw_mask_copy()

        item.setExpanded(True)
        if state.is_raw():
            return
        it = QTreeWidgetItem(item, [name])
        self.file_view.setCurrentItem(it)
        sub_dict[name] = state
        self.state_dict_count[state.file_path] += 1

    def forget(self):
        if not self.forget_btn.isEnabled():
            return
        self.forget_btn.setDisabled(True)
        item: QTreeWidgetItem = self.file_view.currentItem()
        self.forget_action(item)

    def forget_action(self, item):
        if item is None:
            return
        if isinstance(item.parent(), QTreeWidgetItem):
            index = self.file_view.indexOfTopLevelItem(item.parent())
            text = self.file_list[index]
            if item.text(0) not in self.state_dict[text]:
                return
            del self.state_dict[text][item.text(0)]
            parent = item.parent()
            parent.removeChild(item)
            if parent.childCount() == 0:
                self.file_view.takeTopLevelItem(index)
                self.file_list.remove(text)

        else:
            index = self.file_view.indexOfTopLevelItem(item)
            text = self.file_list[index]
            del self.state_dict[text]
            del self.state_dict_count[text]
            self.file_list.remove(text)
            self.file_view.takeTopLevelItem(index)
        QTimer().singleShot(500, self.enable_forget)

    @Slot()
    def enable_forget(self):
        self.forget_btn.setEnabled(True)

    def resizeEvent(self, event: QResizeEvent):
        metric = QFontMetrics(self.file_view.font())
        width = self.file_view.width() - 45
        for i, text in enumerate(self.file_list):
            clipped_text = metric.elidedText(text, Qt.ElideLeft, width)
            item: QTreeWidgetItem = self.file_view.topLevelItem(i)
            item.setText(0, clipped_text)

    def mousePressEvent(self, event: QMouseEvent):
        if event.x() > self.width() - 20:
            self.last_point = event.pos()

    def mouseMoveEvent(self, event: QMouseEvent):
        if event.x() > self.width() - 20:
            QApplication.setOverrideCursor(Qt.SplitHCursor)
        else:
            QApplication.setOverrideCursor(Qt.ArrowCursor)
        if self.last_point is None or not (event.buttons() & Qt.LeftButton):
            return
        new_width = event.x() + 10
        new_width = max(new_width, 150)
        new_width = min(new_width, 600)

        self.setMinimumWidth(new_width)

    def leaveEvent(self, _):  # pylint: disable=R0201
        QApplication.setOverrideCursor(Qt.ArrowCursor)

    def mouseReleaseEvent(self, event: QMouseEvent):
        self.last_point = None

    def set_compare_in_context_menu(self, compare: bool):
        self.file_view.set_show_compare(compare)

    def add_states(self, states: List[ProjectInfoBase]):
        """add multiple states to widget"""
        for el in states:
            self.save_state_action(el, False)
Пример #7
0
class ProcessJobDialog(QDialog):

    disposeDialog = Signal()
    presentInformation = Signal(str, str, str)
    presentError = Signal(str, str, str)

    closeButtonPressed = Signal()
    cancelConfirmed = Signal()

    def __init__(self, title, parent=None):
        QDialog.__init__(self, parent)

        self.__parent = parent
        self.setWindowTitle(title)
        self.setModal(True)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)

        layout = QVBoxLayout()
        layout.setSizeConstraint(QLayout.SetFixedSize)

        widget = QWidget()
        widget_layout = QHBoxLayout()

        size = 64
        spin_movie = resourceMovie("ide/loading.gif")
        spin_movie.setSpeed(60)
        spin_movie.setScaledSize(QSize(size, size))
        spin_movie.start()

        processing_animation = QLabel()
        processing_animation.setMaximumSize(QSize(size, size))
        processing_animation.setMinimumSize(QSize(size, size))
        processing_animation.setMovie(spin_movie)
        widget_layout.addWidget(processing_animation)

        self.processing_label = QLabel("Processing job: '%s'" % title)
        widget_layout.addWidget(self.processing_label, Qt.AlignBottom)

        widget.setLayout(widget_layout)

        layout.addWidget(widget)

        button_layout = QHBoxLayout()
        self.close_button = QPushButton("Close")
        self.close_button.clicked.connect(self.closeButtonPressed.emit)
        button_layout.addStretch()
        button_layout.addWidget(self.close_button)

        layout.addStretch()
        layout.addLayout(button_layout)

        self.setLayout(layout)

        self.disposeDialog.connect(self.reject)
        self.presentInformation.connect(self.__presentInformation)
        self.presentError.connect(self.__presentError)
        self.closeButtonPressed.connect(self.__confirmCancel)

    def disableCloseButton(self):
        self.close_button.setEnabled(False)

    def enableCloseButton(self):
        self.close_button.setEnabled(True)

    def keyPressEvent(self, q_key_event):
        if not self.close_button.isEnabled() and q_key_event.key() == Qt.Key_Escape:
            pass
        else:
            QDialog.keyPressEvent(self, q_key_event)

    def closeEvent(self, close_event):
        close_event.ignore()
        self.closeButtonPressed.emit()

    def __createMsgBox(self, title, message, details):
        msg_box = QMessageBox(self.parent())
        msg_box.setText(title)
        msg_box.setInformativeText(message)

        if len(details) > 0:
            msg_box.setDetailedText(details)

        horizontal_spacer = QSpacerItem(
            500, 0, QSizePolicy.MinimumExpanding, QSizePolicy.Expanding
        )
        layout = msg_box.layout()
        layout.addItem(horizontal_spacer, layout.rowCount(), 0, 1, layout.columnCount())

        return msg_box

    def __presentInformation(self, title, message, details):
        msg_box = self.__createMsgBox(title, message, details)
        msg_box.setIcon(QMessageBox.Information)

        msg_box.exec_()

    def __presentError(self, title, message, details):
        msg_box = self.__createMsgBox(title, message, details)
        msg_box.setIcon(QMessageBox.Critical)

        msg_box.exec_()

    def __confirmCancel(self):
        cancel_box = self.__createMsgBox(
            "Confirm Cancel", "Are you sure you want to cancel the running job?", ""
        )
        cancel_box.setIcon(QMessageBox.Question)
        cancel_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        cancel_box.exec_()

        cancel = cancel_box.result()

        if cancel == QMessageBox.Yes:
            self.cancelConfirmed.emit()
Пример #8
0
    def setup_monitors(self):
        ui = self.ui.monitors
        # Grab a fresh copy, may have been updated
        self.monitors_region_dict = self.ui.regions.get_region_dict()

        # Mark regions which are in use (this gets reset each time we get here)
        #for (i, data) in self.monitors.items():
        #    region = data['region']
        #    if region in self.monitors_region_dict:
        #        self.monitors_region_dict[region]['available'] = False
        self.fixup_monitors_table()
        row = get_selected_row(ui.tablewidget_regions)
        # Autoselect if only 1 row
        if row is None and ui.tablewidget_regions.rowCount() == 1:
            row = 0
            ui.tablewidget_regions.setCurrentCell(row, COLUMN_REGION)
        enabled = (row is not None)
        for item in (ui.toolbutton_delete, ui.bottom_frame):
            item.setEnabled(enabled)

        mon = self.monitors_current_index
        enable_phase = self.monitor_requires_phase(mon)

        #**Fluid phase tab**
        b = ui.pushbutton_fluid
        b.setText(self.fluid_phase_name)
        font = b.font()
        font.setBold(self.monitors_current_tab == FLUID_TAB)
        b.setFont(font)
        w = b.fontMetrics().boundingRect(b.text()).width() + 20
        b.setMaximumWidth(w)
        b.setEnabled(not enable_phase)

        #**Solids Phase Tab** *(Requires TFM Solids)*
        #Each solid phase will have its own tab. The tab name should be the name of the solid
        solids_names = list(self.solids.keys())
        if self.monitors_saved_solids_names != solids_names:
            # Clear out the old ones
            n_cols = ui.tab_layout.columnCount()
            for i in range(n_cols - 1, 0, -1):
                item = ui.tab_layout.itemAtPosition(0, i)
                if not item:
                    continue
                widget = item.widget()
                if not widget:
                    continue
                if widget in (ui.pushbutton_fluid, ui.pushbutton_scalar,
                              ui.pushbutton_reactions, ui.pushbutton_phase):
                    continue
                ui.tab_layout.removeWidget(widget)
                widget.setParent(None)
                widget.deleteLater()
            # And make new ones
            for (i, solid_name) in enumerate(solids_names, 1):
                b = QPushButton(text=solid_name)
                w = b.fontMetrics().boundingRect(solid_name).width() + 20
                b.setMaximumWidth(w)
                b.setFlat(True)
                font = b.font()
                font.setBold(self.monitors_current_tab == SOLIDS_TAB
                             and i == self.monitors_current_solid)
                b.setFont(font)
                b.pressed.connect(
                    lambda i=i: self.monitors_change_tab(SOLIDS_TAB, i))
                ui.tab_layout.addWidget(b, 0, i)

        # Only TFM solids
        for i in range(1, 1 + len(self.solids)):
            enabled = self.project.get_value(
                'solids_model', args=[i]) == 'TFM' and not enable_phase
            item = ui.tab_layout.itemAtPosition(0, i)
            if item:
                widget = item.widget()
            if widget:
                widget.setEnabled(enabled)

        #Scalar (tab) - Tab only available if scalar equations are solved
        # Move the 'Scalar' button to the right of all solids, if needed
        b = ui.pushbutton_scalar
        font = b.font()
        font.setBold(self.monitors_current_tab == SCALAR_TAB)
        b.setFont(font)
        nscalar = self.project.get_value('nscalar', default=0)
        enabled = (nscalar > 0) and not enable_phase
        b.setEnabled(enabled)
        if len(self.solids) != len(self.monitors_saved_solids_names):
            ui.tab_layout.removeWidget(b)
            ui.tab_layout.addWidget(b, 0, 1 + len(self.solids))

        #Reactions (tab) - Tab only available if  nrr > 0
        # Move the 'Reactions' button to the right of all solids, if needed
        b = ui.pushbutton_reactions
        font = b.font()
        font.setBold(self.monitors_current_tab == REACTIONS_TAB)
        b.setFont(font)
        nrr = self.project.get_value('nrr', default=0)
        enabled = (nrr > 0) and not enable_phase
        if nrr == 0 and not enable_phase:
            b.setToolTip("Requires nrr > 0")
        else:
            b.setToolTip('')
        b.setEnabled(enabled)
        if len(self.solids) != len(self.monitors_saved_solids_names):
            ui.tab_layout.removeWidget(b)
            ui.tab_layout.addWidget(b, 0, 2 + len(self.solids))

        # Move the 'Phase' button to the right of all solids, if needed
        b = ui.pushbutton_phase
        font = b.font()
        font.setBold(self.monitors_current_tab == PHASE_TAB)
        b.setFont(font)
        b.setEnabled(enable_phase)
        if len(self.solids) != len(self.monitors_saved_solids_names):
            ui.tab_layout.removeWidget(b)
            ui.tab_layout.addWidget(b, 0, 3 + len(self.solids))

        self.monitors_saved_solids_names = solids_names
        self.P = self.monitors_current_solid

        if mon is None:
            #Construct the GUI, even though disabled (species checkboxes, etc)
            self.monitors_setup_current_tab()
            return

        key = 'monitor_name'
        le = ui.lineedit_keyword_monitor_name_args_MONITOR
        val = self.project.get_value(key, args=[mon])
        if val is None:  # Construct from region name
            val = self.monitor_default_name(self.monitors_current_region)
            self.update_keyword(key, val, args=[mon])
        le.updateValue(key, val)
        # Update table too
        tw = ui.tablewidget_regions
        for i in range(tw.rowCount()):
            data = tw.item(i, 0).data(UserRole)
            index, name = data
            if index == mon:
                tw.item(i, COLUMN_FILENAME).setText(val)

        #Specify write interval
        key = 'monitor_dt'
        default = 0.05
        le = ui.lineedit_keyword_monitor_dt_args_MONITOR
        val = self.project.get_value(key, args=[mon])
        if val is None:
            val = default
            self.update_keyword(key, val, args=[mon])
        le.updateValue(key, val)

        # Don't stay on a disabled tab
        index = self.monitors_tab_to_index(self.monitors_current_tab,
                                           self.monitors_current_solid)
        item = None if index is None else ui.tab_layout.itemAtPosition(
            0, index)
        b = item.widget() if item else None
        if ui.isEnabled() and not (b and b.isEnabled()):
            self.monitors_change_tab(*self.monitors_find_valid_tab())
        else:
            self.monitors_setup_current_tab()

        # make sure underline is in the right place, as # of solids may
        # have changed (lifted from animate_stacked_widget, which we
        # don't want to call here)
        tab = self.monitors_current_tab
        line_to = self.monitors_tab_to_index(tab, self.monitors_current_solid)
        line = ui.tab_underline
        btn_layout = ui.tab_layout
        if line_to is not None:
            btn_layout.addItem(btn_layout.takeAt(btn_layout.indexOf(line)), 1,
                               line_to)
Пример #9
0
    def setup_pss(self):
        ui = self.ui.point_sources

        # Grab a fresh copy, may have been updated
        self.pss_region_dict = self.ui.regions.get_region_dict()

        # Mark regions which are in use (this gets reset each time we get here)
        for (i, data) in self.pss.items():
            region = data['region']
            if region in self.pss_region_dict:
                self.pss_region_dict[region]['available'] = False

        self.fixup_pss_table(ui.tablewidget_regions)
        row = get_selected_row(ui.tablewidget_regions)
        # Autoselect if only 1 row
        if row is None and ui.tablewidget_regions.rowCount() == 1:
            row = 0
            ui.tablewidget_regions.setCurrentCell(row, 0)
        enabled = (row is not None)
        for item in (ui.toolbutton_delete, ui.bottom_frame):
            item.setEnabled(enabled)

        #Tabs group point source parameters for phases. Tabs are unavailable if no input
        #is required from the user.
        #    Fluid tab - Unavailable if the fluid phase was disabled.
        b = ui.pushbutton_fluid
        b.setText(self.fluid_phase_name)
        b.setEnabled(not self.fluid_solver_disabled)
        font = b.font()
        font.setBold(self.pss_current_tab == 0)
        b.setFont(font)

        # Each solid phase will have its own tab. The tab name should be the name of the solid
        solids_names = list(self.solids.keys())
        if self.pss_saved_solids_names != solids_names:
            # Clear out the old ones
            n_cols = ui.tab_layout.columnCount()
            for i in range(n_cols - 1, 0, -1):
                item = ui.tab_layout.itemAtPosition(0, i)
                if not item:
                    continue
                widget = item.widget()
                if not widget:
                    continue
                if widget == ui.pushbutton_fluid:
                    continue
                ui.tab_layout.removeWidget(widget)
                widget.setParent(None)
                widget.deleteLater()
            # And make new ones
            for (i, solid_name) in enumerate(solids_names, 1):
                b = QPushButton(text=solid_name)
                w = b.fontMetrics().boundingRect(solid_name).width() + 20
                b.setMaximumWidth(w)
                b.setFlat(True)
                font = b.font()
                font.setBold(self.pss_current_tab == SOLIDS_TAB
                             and i == self.pss_current_solid)
                b.setFont(font)
                ui.tab_layout.addWidget(b, 0, i)
                b.pressed.connect(
                    lambda i=i: self.pss_change_tab(SOLIDS_TAB, i))

        for (i, solid_name) in enumerate(self.solids.keys(), 1):
            model = self.project.get_value('solids_model', args=[i])
            #At this time, only TFM solids can be defined with point sources.
            #At some point in the future, this could be extended to PIC solids, but never DEM.
            b = ui.tab_layout.itemAtPosition(0, i).widget()
            if model == 'TFM':
                b.setEnabled(True)
                b.setToolTip(None)
            else:
                b.setEnabled(False)
                b.setToolTip("Only TFM solids can be defined as point sources"
                             "")

        self.pss_saved_solids_names = solids_names
        self.P = self.pss_current_solid

        # Don't stay on a disabled tab
        index = self.pss_tab_to_index(self.pss_current_tab,
                                      self.pss_current_solid)
        item = None if index is None else ui.tab_layout.itemAtPosition(
            0, index)
        b = item.widget() if item else None
        if ui.isEnabled() and not (b and b.isEnabled()):
            self.pss_change_tab(*self.pss_find_valid_tab())
        else:
            self.pss_setup_current_tab()

        # make sure underline is in the right place, as # of solids may
        # have changed (lifted from animate_stacked_widget, which we
        # don't want to call here)
        tab = self.pss_current_tab
        line_to = self.pss_tab_to_index(tab, self.pss_current_solid)
        line = ui.tab_underline
        btn_layout = ui.tab_layout
        if line_to is not None:
            btn_layout.addItem(btn_layout.takeAt(btn_layout.indexOf(line)), 1,
                               line_to)