Пример #1
0
class Window(QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        # Set size and centre window
        self.setGeometry(50, 50, 500, 400)
        qtRectangle = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)

        self.move(qtRectangle.topLeft())

        self.setWindowTitle("Rthenticator")
        self.setWindowIcon(QIcon('icon.ico'))
        self.setStyleSheet("background-color: #2F3031")

        self.home()

    def home(self):
        # Init QSystemTrayIcon
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon('icon.ico'))
        show_action = QAction("Show", self)
        quit_action = QAction("Exit", self)
        hide_action = QAction("Hide", self)
        show_action.triggered.connect(self.show)
        hide_action.triggered.connect(self.hide)
        quit_action.triggered.connect(qApp.quit)
        tray_menu = QMenu()
        tray_menu.addAction(show_action)
        tray_menu.addAction(hide_action)
        tray_menu.addAction(quit_action)
        self.tray_icon.setContextMenu(tray_menu)
        self.tray_icon.activated.connect(self.systemIcon)
        self.tray_icon.show()

        # Button Setup
        self.btnImport = QPushButton("Import", self)
        self.btnImport.move(50, 320)
        self.btnImport.setStyleSheet(
            "background-color: #737C7D; color: #E9E6E4")
        self.btnImport.clicked.connect(self.btnImportClicked)

        # Listbox Setup
        self.Listbox = QListWidget(self)
        self.Listbox.setAlternatingRowColors(True)
        self.Listbox.setFixedSize(220, 300)
        self.Listbox.move(10, 10)
        self.Listbox.setStyleSheet(
            "alternate-background-color: #3F4041; color: #E9E6E4;")
        self.Listbox.itemClicked.connect(self.listboxClicked)
        for key in sorted(secrets):
            self.Listbox.addItem(key)
        self.Listbox.setCurrentRow(0)
        self.Listbox.currentItem().setSelected(True)
        # Listview context menu
        self.Listbox.setContextMenuPolicy(Qt.CustomContextMenu)
        self.Listbox.customContextMenuRequested.connect(self.showMenu)
        self.Listbox.itemChanged.connect(self.listboxChanged)
        self.old_name = ""

        # Frame Setup
        self.Frame = QFrame(self)
        self.Frame.setFixedSize(220, 300)
        self.Frame.move(266, 10)
        self.Frame.setFrameShape(QFrame.Shape.Panel)
        self.Frame.setFrameShadow(QFrame.Shadow.Plain)
        self.Frame.setStyleSheet("color: #828790")

        # Progress Bar Setup
        self.progress = QProgressBar(self)
        self.progress.setGeometry(266, 325, 200, 20)
        self.progress.setTextVisible(False)
        self.progress.setStyleSheet(
            "QProgressBar::chunk { background: #6187CB; }")
        self.progress.setRange(1, 29)

        # Progress Bar Timer Setup
        self.timer = QTimer()
        self.timer.timeout.connect(self.progressTimer)
        self.timer.start(1000)

        # Label Setup
        self.label = QLabel(self)
        self.label.setGeometry(310, 220, 150, 40)
        self.label.setText("")
        self.label.setFont(QFont("Arial", 30, QFont.Bold))
        self.label.setStyleSheet("color: #E9E6E4")
        self.label.setTextInteractionFlags(Qt.TextSelectableByMouse)

        self.image = QLabel(self)
        self.image.setGeometry(300, 40, 150, 150)

        self.Listbox.setFocus(True)
        self.listboxClicked()
        self.show()

    # Restore view when tray icon doubleclicked
    def systemIcon(self, reason):
        if reason == QSystemTrayIcon.DoubleClick:
            self.show()
            self.copy_auth_code()

    # Override closeEvent, to intercept the window closing event
    def closeEvent(self, event):
        event.ignore()
        self.hide()
        self.tray_icon.showMessage("Tray Program",
                                   "Application was minimized to Tray",
                                   QSystemTrayIcon.Information, 2000)

    def copy_auth_code(self):
        """
        Copies Authentication code to the clipboard
        """
        answer = self.Listbox.currentItem().text()
        totp = pyotp.TOTP(secrets[answer][0])
        self.label.setText(str(totp.now()))
        pyperclip.copy(totp.now())

    def progressTimer(self):
        """
        Updates progress timer
        Copies authentication code to clipboard once timer has reached 0 and main window is not in system tray
        """
        current_time = int(time.time() % 30)
        self.progress.setValue(current_time)
        if current_time == 0:
            if self.isVisible():
                self.copy_auth_code()

    def setImage(self):
        """
        Reads from the images directory to see if there is a matching logo and must be the same name
        Splits the text on a `:`
        png files only
        """
        item = self.Listbox.currentItem().text().split(":")[0]
        fname = f"images/{item}.png"
        if os.path.isfile(fname):
            pixmap = QPixmap(fname).scaled(150, 150)
            self.image.setPixmap(pixmap)
        else:
            self.image.setPixmap(QPixmap())

    def listboxClicked(self):
        """
        Listbox has been clicked
        """
        self.setImage()
        self.copy_auth_code()

    def btnImportClicked(self):
        """
        Imports a QR-code png file and add its to secrets.json
        """
        fileName, _ = QFileDialog.getOpenFileName(
            self, "QFileDialog.getOpenFileName()", "", "All Files (*)")
        if fileName:
            test = unquote(
                decode(Image.open(fileName))[0].data.decode("utf-8"))
            query = urlsplit(test).query
            params = parse_qs(query)
            start = "/totp/"
            end = "\\?"
            test = re.search(f'{start}(.*){end}', test).group(1)
            secrets[test] = [params['secret'][0]]
            self.Listbox.addItem(test)
            with open('secrets.json', 'w') as fh:
                json.dump(secrets, fh, sort_keys=True, indent=4)

    def showMenu(self, pos):
        """
        Displays right click context menu, with 2 options
        - Rename - Allows us to rename an entry
        - Delete - Aloows us to remove and entry
        """
        menu = QMenu()
        renameAction = menu.addAction("Rename")
        deleteAction = menu.addAction("Delete")
        action = menu.exec_(self.Listbox.viewport().mapToGlobal(pos))
        if action == renameAction:
            this_item = self.Listbox.currentItem()
            self.Listbox.blockSignals(
                True
            )  # Block signals so we dont trigger the listboxChanged function
            this_item.setFlags(
                this_item.flags()
                | Qt.ItemIsEditable)  # Allows us to edit the item
            self.Listbox.blockSignals(False)  # Re-enables signals
            self.old_name = this_item.text()
            self.Listbox.edit(self.Listbox.currentIndex())
        if action == deleteAction:
            self.showMessageBox()

    def showMessageBox(self):
        """
        Creates and displays a message box for delete confirmation
        """
        box = QMessageBox()
        box.setIcon(QMessageBox.Question)
        box.setWindowTitle('Warning!')
        box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        box.setStyleSheet("background-color: #2F3031;")
        box.setText(
            "<FONT COLOR='#E9E6E4'>Do you really wish to delete this?</FONT>")
        btnYes = box.button(QMessageBox.Yes)
        btnYes.setStyleSheet("background-color: #737C7D; color: #E9E6E4")
        btnYes.setText('Yes')
        btnNo = box.button(QMessageBox.No)
        btnNo.setStyleSheet("background-color: #737C7D; color: #E9E6E4")
        btnNo.setText('No')
        box.exec_()

        if box.clickedButton() == btnYes:
            items = self.Listbox.selectedItems()
            for item in items:
                new_name = item.text()
                self.Listbox.takeItem(self.Listbox.row(item))
                secrets.pop(new_name)
                with open('secrets.json', 'w') as fh:
                    json.dump(secrets, fh, sort_keys=True, indent=4)

    def listboxChanged(self):
        """
        Called when we have changed text of an item in the listbox
        """
        new_name = self.Listbox.currentItem().text()
        self.Listbox.blockSignals(
            True)  # Block signals so we dont trigger ourselves
        this_item = self.Listbox.currentItem()
        this_item.setFlags(this_item.flags()
                           & ~Qt.ItemIsEditable)  # Turn off the Editable flag
        self.Listbox.blockSignals(False)  # Re-enables signals to be processed
        secrets[new_name] = secrets.pop(self.old_name)
        with open('secrets.json', 'w') as fh:
            json.dump(secrets, fh, sort_keys=True, indent=4)
Пример #2
0
class CreateQuizWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.DEFAULT_BLOCK = (10, 100, [('Вопрос №1', ['Ответ №1',
                                                       'Ответ №2'], 0)])
        self.blocks = [self.DEFAULT_BLOCK]
        self.questions = self.blocks[0][2]
        self.cur_block = 0
        self.cur_question = -1
        self.initUI()

    def initUI(self):
        self.move(*COORDS)
        self.setWindowTitle('pyQuiz')

        self.title_edit = QLineEdit()
        self.title_edit.setPlaceholderText('Название викторины')
        self.title_edit.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)

        self.prev_block_button = QPushButton()
        self.prev_block_button.setIcon(QIcon('assets/back.png'))
        self.prev_block_button.setFixedWidth(30)
        self.prev_block_button.setEnabled(False)
        self.prev_block_button.clicked.connect(self.prevBlock)

        self.next_block_button = QPushButton()
        self.next_block_button.setIcon(QIcon('assets/plus.png'))
        self.next_block_button.setFixedWidth(30)
        self.next_block_button.clicked.connect(self.nextBlock)

        self.delete_block_button = QPushButton()
        self.delete_block_button.setIcon(QIcon('assets/cross.png'))
        self.delete_block_button.setFixedWidth(30)
        self.delete_block_button.setEnabled(False)
        self.delete_block_button.clicked.connect(self.delBlock)

        self.block_name_label = QLabel('Блок №1')
        self.block_name_label.setAlignment(Qt.AlignCenter | Qt.AlignHCenter)

        self.block_time_limit = QLineEdit()
        self.block_time_limit.setPlaceholderText('Время на вопрос')

        self.block_points = QLineEdit()
        self.block_points.setPlaceholderText('Очки за вопрос')

        self.add_question_button = QPushButton()
        self.add_question_button.setIcon(QIcon('assets/plus.png'))
        self.add_question_button.clicked.connect(self.addQuestion)

        self.delete_question_button = QPushButton()
        self.delete_question_button.setIcon(QIcon('assets/cross.png'))
        self.delete_question_button.clicked.connect(self.deleteQuestion)

        self.questions_list = QListWidget()
        self.questions_list.setFixedWidth(150)
        self.questions_list.itemSelectionChanged.connect(self.switchQuestion)

        self.question_text_edit = QLineEdit()
        self.question_text_edit.setPlaceholderText('Текст вопроса')

        self.options_list = QListWidget()

        self.exit_button = QPushButton()
        self.exit_button.clicked.connect(self.exit)

        self.exit_button.setText('Назад')
        self.exit_button.setStyleSheet(
            'QPushButton{font-size:30px;text-align:center;background-color:#3C3F41;color:#BBBBBB;}'
        )

        self.save_button = QPushButton()
        self.save_button.setText('Сохранить')
        self.save_button.setStyleSheet(
            'QPushButton{font-size:30px;text-align:center;background-color:#3C3F41;color:#BBBBBB;}'
        )
        self.save_button.clicked.connect(self.save)

        self.add_option_button = QPushButton()
        self.add_option_button.setIcon(QIcon('assets/plus.png'))
        self.add_option_button.clicked.connect(self.addOption)

        self.delete_option_button = QPushButton()
        self.delete_option_button.setIcon(QIcon('assets/cross.png'))
        self.delete_option_button.clicked.connect(self.delOption)

        vbox = QVBoxLayout()

        menu_layout = QHBoxLayout()
        menu_layout.addWidget(self.prev_block_button)
        menu_layout.addWidget(self.block_name_label)
        menu_layout.addWidget(self.delete_block_button)
        menu_layout.addWidget(self.next_block_button)

        block_settings = QHBoxLayout()
        block_settings.addWidget(self.block_time_limit)
        block_settings.addWidget(self.block_points)

        main_layout = QHBoxLayout()

        block_table_layout = QVBoxLayout()
        block_table_layout.addWidget(self.questions_list)
        change_block_layout = QHBoxLayout()
        change_block_layout.addWidget(self.add_question_button)
        change_block_layout.addWidget(self.delete_question_button)
        block_table_layout.addLayout(change_block_layout)

        main_layout.addLayout(block_table_layout)
        question_layout = QVBoxLayout()

        question_layout.addWidget(self.question_text_edit)
        question_layout.addWidget(self.options_list)
        change_question_layout = QHBoxLayout()
        change_question_layout.addWidget(self.add_option_button)
        change_question_layout.addWidget(self.delete_option_button)
        question_layout.addLayout(change_question_layout)

        main_layout.addLayout(question_layout)

        footer_menu = QHBoxLayout()
        footer_menu.addWidget(self.exit_button)
        footer_menu.addWidget(self.save_button)

        vbox.addWidget(self.title_edit)
        vbox.addLayout(menu_layout)
        vbox.addLayout(block_settings)
        vbox.addLayout(main_layout)
        vbox.addLayout(footer_menu)

        self.restoreBlock()

        self.setLayout(vbox)
        self.setStyleSheet(QUIZ_STYLE_SHEET)
        self.setFixedSize(500, 500)

    def blockNavUpdate(self):
        if self.cur_block == len(self.blocks) - 1:
            self.next_block_button.setIcon(QIcon('assets/plus.png'))
        else:
            self.next_block_button.setIcon(QIcon('assets/next.png'))
        self.prev_block_button.setEnabled(self.cur_block > 0)
        self.next_block_button.setEnabled(
            self.cur_block < QUIZ_BLOCKS_NUM_RANGE.stop - 1)
        self.delete_block_button.setEnabled(len(self.blocks) > 1)
        self.block_name_label.setText(f'Блок № {self.cur_block + 1}')

    def showMsg(self, s, type=QMessageBox.Critical):
        msg = QMessageBox()
        msg.setIcon(type)
        msg.setText(s)
        msg.setWindowTitle('pyQuiz')
        msg.exec_()

    def saveBlock(self):
        if self.cur_question != -1:
            if not self.saveQuestion():
                return False
        time = self.block_time_limit.text()
        points = self.block_points.text()
        if not time.isnumeric():
            self.showMsg('Время на вопрос должно быть целым числом!')
            return False
        time = int(time)
        if time not in QUIZ_BLOCK_TIME_RANGE:
            self.showMsg(
                f'Время на вопрос должно быть не меньше {QUIZ_BLOCK_TIME_RANGE.start}, '
                f'но меньше {QUIZ_BLOCK_TIME_RANGE.stop}')
            return False
        if not points.isnumeric():
            self.showMsg('Кол-во очков за вопрос должно быть целым числом!')
            return False
        points = int(points)
        if points not in QUIZ_BLOCK_POINTS_RANGE:
            self.showMsg(
                f'Кол-во очков за вопрос должно быть не меньше {QUIZ_BLOCK_POINTS_RANGE.start}, '
                f'но меньше {QUIZ_BLOCK_POINTS_RANGE.stop}')
            return False
        if len(self.questions) not in QUIZ_QUESTIONS_NUM_RANGE:
            self.showMsg(
                f'Кол-во вопросов в блоке должно быть не меньше {QUIZ_QUESTIONS_NUM_RANGE.start}, '
                f'но меньше {QUIZ_QUESTIONS_NUM_RANGE.stop}')
            return False
        self.blocks[self.cur_block] = (time, points, self.questions)
        return True

    def restoreBlock(self):
        block = self.blocks[self.cur_block]
        self.block_time_limit.setText(str(block[0]))
        self.block_points.setText(str(block[1]))
        self.questions_list.clear()
        for question_text, options, right_option in block[2]:
            self.questions_list.addItem(question_text)
        self.questions = block[2][:]
        self.cur_question = -1
        self.questions_list.clearSelection()
        self.question_text_edit.setText('')
        self.options_list.clear()
        self.cur_question = -1

    def nextBlock(self):
        if not self.saveBlock():
            return
        self.cur_block += 1
        if self.cur_block == len(self.blocks):
            self.blocks.append(self.DEFAULT_BLOCK)
        self.blockNavUpdate()
        self.restoreBlock()

    def prevBlock(self):
        if not self.saveBlock():
            return
        self.cur_block -= 1
        self.blockNavUpdate()
        self.restoreBlock()

    def delBlock(self):
        self.blocks.pop(self.cur_block)
        if self.cur_block == len(self.blocks):
            self.cur_block -= 1
        self.blockNavUpdate()
        self.restoreBlock()

    def switchQuestion(self):
        if len(self.questions_list.selectedIndexes()) == 0:
            return
        if self.cur_question != -1:
            if not self.saveQuestion():
                self.questions_list.blockSignals(True)
                self.questions_list.clearSelection()
                self.questions_list.item(self.cur_question).setSelected(True)
                self.questions_list.blockSignals(False)
                return
        self.cur_question = self.questions_list.selectedIndexes()[0].row()
        self.restoreQuestion()

    def addQuestion(self):
        question_text, okBtnPressed = QInputDialog.getText(
            self, 'Создание вопроса', 'Введите текст вопроса')
        if not okBtnPressed:
            return
        if len(question_text) not in QUIZ_QUESTION_TEXT_LEN_RANGE:
            self.showMsg(
                f'Длина вопроса должна быть не меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.start}, '
                f'но меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.stop}',
                QMessageBox.Critical)
            return
        i = -1
        if len(self.questions_list.selectedIndexes()) > 0:
            i = self.questions_list.selectedIndexes()[0].row()
        i += 1
        self.questions.insert(i, (question_text, ['Ответ №1', 'Ответ №2'], 0))
        self.questions_list.insertItem(i, question_text)
        self.delete_question_button.setEnabled(True)

    def deleteQuestion(self):
        if len(self.questions_list.selectedIndexes()) == 0:
            return
        i = self.questions_list.selectedIndexes()[0].row()
        self.questions_list.takeItem(i)
        self.questions.pop()
        self.cur_question = -1

    def saveQuestion(self):
        question_text = self.question_text_edit.text()
        if len(question_text) not in QUIZ_QUESTION_TEXT_LEN_RANGE:
            self.showMsg(
                f'Длина текста вопроса должна быть не меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.start}, '
                f'но меньше {QUIZ_QUESTION_TEXT_LEN_RANGE.stop}',
                QMessageBox.Critical)
            return False
        self.questions_list.item(self.cur_question).setText(question_text)
        options = []
        for i in range(len(self.options_list)):
            options.append(self.options_list.item(i).text())
        if len(options) not in QUIZ_OPTIONS_NUM_RANGE:
            self.showMsg(
                f'Кол-во ответов на вопрос должно быть не меньше {QUIZ_OPTIONS_NUM_RANGE.start}, '
                f'но меньше {QUIZ_OPTIONS_NUM_RANGE.stop}',
                QMessageBox.Critical)
            return False
        if len(self.options_list.selectedIndexes()) != 1:
            self.showMsg(f'Не выбран правильный ответ!', QMessageBox.Critical)
            return False
        right_answer = self.options_list.selectedIndexes()[0].row()
        self.questions[self.cur_question] = (question_text, options,
                                             right_answer)
        return True

    def restoreQuestion(self):
        question = self.questions[self.cur_question]
        self.question_text_edit.setText(question[0])
        self.options_list.clear()
        for option in question[1]:
            self.options_list.addItem(option)
        self.options_list.item(question[2]).setSelected(True)

    def addOption(self):
        option_text, okBtnPressed = QInputDialog.getText(
            self, 'Создание ответа', 'Введите текст ответа')
        if not okBtnPressed:
            return
        if len(option_text) not in QUIZ_OPTION_TEXT_LEN_RANGE:
            self.showMsg(
                f'Длина ответа должна быть не меньше {QUIZ_OPTION_TEXT_LEN_RANGE.start}, '
                f'но меньше {QUIZ_OPTION_TEXT_LEN_RANGE.stop}',
                QMessageBox.Critical)
            return
        self.options_list.addItem(option_text)

    def delOption(self):
        for index in self.options_list.selectedIndexes():
            self.options_list.takeItem(index.row())

    def save(self):
        if not self.saveBlock():
            return
        quiz_name = self.title_edit.text()
        if len(quiz_name) not in QUIZ_NAME_LEN_RANGE:
            self.showMsg(
                f'Длина названия викторины должна быть не меньше {QUIZ_NAME_LEN_RANGE.start}, '
                f'но меньше {QUIZ_NAME_LEN_RANGE.stop}')
            return
        quiz_json = {'name': quiz_name}
        cur = 0
        for time, pts, questions in self.blocks:
            for text, options, right_answer in questions:
                quiz_json[str(cur)] = {
                    'time': time,
                    'score': pts,
                    'question': text,
                    'answers': list(options),
                    'true': right_answer
                }
                cur += 1
        # QUIZ_SAVE_DIR
        file_name_preffix = secrets.token_hex(5)
        while os.path.isfile(os.path.join(QUIZ_SAVE_DIR, file_name_preffix)):
            file_name_preffix = secrets.token_hex(5)
        # https://stackoverflow.com/questions/18337407/saving-utf-8-texts-in-json-dumps-as-utf8-not-as-u-escape-sequence
        file_path = os.path.join(QUIZ_SAVE_DIR,
                                 quiz_name + '_' + file_name_preffix + '.json')
        with open(file_path, 'w', encoding='utf8') as json_file:
            json.dump(quiz_json,
                      json_file,
                      ensure_ascii=False,
                      sort_keys=True,
                      indent=4)
        self.exit()

    def exit(self):
        global COORDS
        COORDS = [self.x(), self.y()]
        self.create_game_window = QuizSelectionWindow()
        self.create_game_window.show()
        self.close()
Пример #3
0
class SongList(QWidget):
    def __init__(self, parent=None):
        super(SongList, self).__init__(parent)

        os.chdir(os.path.dirname(os.path.abspath(__file__)))
        resourcesPath = os.getcwd()
        resourcesPath = os.path.join(resourcesPath, "resources")

        self.PLAY_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "play.png")))
        self.PAUSE_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "pause.png")))
        self.STOP_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "stop.png")))
        self.DELETE_ICON = QIcon(QPixmap(os.path.join(resourcesPath, "delete.png")))

        self.setupMediaPlayer()
        self.setupUi()

    def setupMediaPlayer(self):
        self.mediaPlayer = QMediaPlayer()

        self.mediaPlayer.setNotifyInterval(1)
        self.mediaPlayer.stateChanged.connect(self.mediaStateChanged)
        self.mediaPlayer.positionChanged.connect(self.positionChanged)
        self.mediaPlayer.durationChanged.connect(self.durationChanged)

    def setupUi(self):
        self.setWindowTitle("List of songs")
        mainLayout = QHBoxLayout(self)

        verticalListLayout = QVBoxLayout()
        self.songsListWidget = QListWidget()
        self.songsListWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.songsListWidget.customContextMenuRequested.connect(self.listWidgetRightClick)
        verticalListLayout.addWidget(self.songsListWidget)

        miniHorizontalLayout = QHBoxLayout()
        locatorLine = QLineEdit()
        locatorLine.setPlaceholderText("Locator")
        locatorBox = QComboBox()
        items = ["Title", "Status", "Description", "Style", "All"]
        locatorBox.addItems(items)
        locatorBox.setCurrentIndex(len(items)-1)

        miniHorizontalLayout.addWidget(locatorLine)
        miniHorizontalLayout.addWidget(locatorBox)

        locatorLine.textChanged.connect(lambda:self.populateList(locatorLine.text(), locatorBox.currentText()))

        verticalListLayout.addLayout(miniHorizontalLayout)

        self.mainForm = QGroupBox()
        self.mainForm.setTitle("Details")

        mainLayout.addLayout(verticalListLayout)
        mainLayout.addWidget(self.mainForm)

        self.populateList()
        self.mainFormSetupUi()
        #self.show()

        self.songsListWidget.currentRowChanged.connect(self.changePage)
    
    def mainFormSetupUi(self):

        """title, status style, duration, descriptin, location, project,
        variation_another_song, timestamp"""

        mainLayout = QVBoxLayout(self.mainForm)

        #Horizontal Layout 1
        horizontalLayout1 = QHBoxLayout()

        titleLabel = QLabel("Song name:")
        self.titleEdit = QLineEdit()

        self.titleEdit.editingFinished.connect(self.checkSong)
        self.titleEdit.textChanged.connect(self.validateSong)

        horizontalLayout1.addWidget(titleLabel)
        horizontalLayout1.addWidget(self.titleEdit)


        #Horizontal Layout 2
        horizontalLayout2 = QHBoxLayout()
        statusLabel = QLabel("Status:")
        self.statusBox = QComboBox()

        dateLabel = QLabel("Date:")
        self.dateEdit = QDateTimeEdit()
        self.dateEdit.setCalendarPopup(True)

        horizontalLayout2.addWidget(statusLabel)
        horizontalLayout2.addWidget(self.statusBox)
        horizontalLayout2.addStretch(1)
        horizontalLayout2.addWidget(dateLabel)
        horizontalLayout2.addWidget(self.dateEdit)


        #Style Groupbox, widgets added automatically
        self.styleGroupBox = QGroupBox()
        self.styleGroupBox.setTitle("Style:")
        self.styleLayout = QGridLayout(self.styleGroupBox)

        horizontalLayout3 = QHBoxLayout()
        durationLabel = QLabel("Duration:")
        self.durationLine = QTimeEdit()
        self.durationLine.setDisplayFormat("mm:ss")

        projectLabel = QLabel("Project")

        self.projectComboBox = QComboBox()
        self.projectComboBox.setEditable(True)

        horizontalLayout3.addWidget(durationLabel)
        horizontalLayout3.addWidget(self.durationLine)
        horizontalLayout3.addWidget(projectLabel)
        horizontalLayout3.addWidget(self.projectComboBox)

        horizontalLayout4 = QHBoxLayout()
        descriptionLabel = QLabel("Description:")
        variationLabel = QLabel("Variation from another song: ")
        self.variationLine = QLineEdit()

        horizontalLayout4.addWidget(descriptionLabel)
        horizontalLayout4.addStretch(1)
        horizontalLayout4.addWidget(variationLabel)
        horizontalLayout4.addWidget(self.variationLine)

        self.descriptionTextEdit = QTextEdit()

        horizontalLayout5 = QHBoxLayout()
        locationLabel = QLabel("Location:")
        self.locationLine = QLineEdit()
        self.locationButton = QPushButton("...")
        self.locationButton.clicked.connect(self.locateFile)


        horizontalLayout5.addWidget(locationLabel)
        horizontalLayout5.addWidget(self.locationLine)
        horizontalLayout5.addWidget(self.locationButton)

        horizontalLayout6 = QHBoxLayout()
        self.slider = QSlider(Qt.Horizontal)
        self.slider.sliderReleased.connect(self.playSlider)
        self.slider.setStyleSheet("QSlider::handle:horizontal { border: 1px solid #777; background:#b55858;}")
        horizontalLayout6.addWidget(self.slider)

        horizontalLayout7 = QHBoxLayout()
        self.playButton = QPushButton()
        self.stopButton = QPushButton()

        self.playButton.setIcon(self.PLAY_ICON)
        self.stopButton.setIcon(self.STOP_ICON)

        self.playButton.clicked.connect(self.playSong)
        self.stopButton.clicked.connect(self.stopSong)

        horizontalLayout7.addStretch(1)
        horizontalLayout7.addWidget(self.playButton)
        horizontalLayout7.addWidget(self.stopButton)
        horizontalLayout7.addStretch(1)


        horizontalLayout8 = QHBoxLayout()
        self.saveButton = QPushButton()
        self.saveButton.setText("Save")
        self.saveButton.clicked.connect(self.saveSong)

        horizontalLayout8.addStretch(1)
        horizontalLayout8.addWidget(self.saveButton)

        mainLayout.addLayout(horizontalLayout1)
        mainLayout.addLayout(horizontalLayout2)
        mainLayout.addWidget(self.styleGroupBox)
        mainLayout.addLayout(horizontalLayout3)
        mainLayout.addLayout(horizontalLayout4)
        mainLayout.addWidget(self.descriptionTextEdit)
        mainLayout.addLayout(horizontalLayout5)
        mainLayout.addLayout(horizontalLayout6)
        mainLayout.addLayout(horizontalLayout7)
        mainLayout.addLayout(horizontalLayout8)

    def clearForm(self):
        self.titleEdit.clear()
        self.statusBox.clear()
        for widget in self.styleGroupBox.children():
            if not isinstance(widget, QGridLayout):
                widget.deleteLater()

        self.durationLine.clear()
        self.projectComboBox.clear()
        self.variationLine.clear()
        self.descriptionTextEdit.clear()
        self.locationLine.clear()

    def changePage(self, index):
        title = self.songsListWidget.item(index).data(Qt.UserRole)
        self.clearForm()
        self.populateForm(title)
        self.slider.setValue(0)

    def populateForm(self, title): #title is the primary key
        listArray = queries("""SELECT title, status, style, duration, description,
        location, project, variation_another_song, timestamp from songs WHERE title = ?""", (title,))
        print(listArray)
        if len(listArray) != 0:
            title = listArray[0][0]
            status = listArray[0][1]

            styles = []
            styleArray = listArray[0][2]
            if styleArray != None:
                if "," in styleArray:
                    styles = styleArray.split(",")
                else:
                    styles.append(styleArray)
            duration = listArray[0][3]
            description = listArray[0][4]
            location = listArray[0][5]
            project = listArray[0][6]
            variation_another_song = listArray[0][7]
            timestamp = listArray[0][8]
        else:
            title = None
            status = None
            styles = None
            duration = None
            description = None
            location = None
            project = None
            variation_another_song = None
            timestamp = None

        if title != None: self.titleEdit.setText(title)

        self.statusBox.addItems(["Select...", "Demo", "WIP", "Idea", "Unfinished song", "EQ", "Master", "Finished"])
        if status != None: self.statusBox.setCurrentText(status)
        if timestamp != None: self.dateEdit.setDateTime(datetime.strptime(timestamp, '%d/%m/%Y %H:%M'))
        else: self.dateEdit.setDateTime(datetime.now())#default

        styleArray = queries("select style from songs where style is not null")

        """
        print(styleArray)
        if styleArray != None:
            styleArray = styleArray[0][0]
            if "," in styleArray:
                styles = styleArray.split(",")
            else:
                styles.append(styleArray)"""

        stylesArray = []

        query = queries("select style from songs where style is not null")
        if len(query) != 0:
            for style in query:
                stylesMiniArray = style[0].split(",")
                stylesMiniArray = list(filter(None, stylesMiniArray))
                for item in stylesMiniArray:
                    if item not in stylesArray:
                        if item != '':
                            stylesArray.append(item)

        self.x = 0
        self.y = 0

        if len(stylesArray) != 0:
            for style in stylesArray:
                    print("style", style)
                    checkBox = QCheckBox(style)
                    self.styleLayout.addWidget(checkBox, self.x, self.y)
                    self.checkBoxPositionAsignment()
        self.addStyle()

        if styles!= None:
            if len(styles) != 0:
                for style in styles:
                    for checkbox in self.styleGroupBox.children():
                        if isinstance(checkbox, QCheckBox):
                            if checkbox.text() == style:
                                checkbox.setChecked(True)

        if duration != None:
                time = QTime(0,0,0)
                self.durationLine.setTime(time.addSecs(duration))

        projectsArray = ["Select..."]
        projectsArrayQuery = queries("SELECT project from songs")
        if len(projectsArrayQuery) != 0:
            for project in projectsArrayQuery[0]:
                if project not in projectsArray:
                    projectsArray.append(project)
        if project != None: self.projectComboBox.setCurrentText(project)

        if variation_another_song != None: self.variationLine.setText(variation_another_song)
        if description != None: self.descriptionTextEdit.setText(description)

        available = False
        if location != None:
            self.locationLine.setText(location)
        if len(self.locationLine.text()) != 0:
            try:
                self.playlist = QMediaPlaylist()
                self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(location)))
                self.mediaPlayer.setPlaylist(self.playlist)
            except:
                pass
            available = True#I know this is stupid but just in case

        self.slider.setVisible(available)
        self.playButton.setVisible(available)
        self.stopButton.setVisible(available)

    def populateList(self, locatorItem=None, locatorColumn=None):
        print(locatorItem, locatorColumn)
        self.songsListWidget.blockSignals(True)
        self.songsListWidget.clear()
        if locatorItem == None or locatorItem == "":
            listArray = queries("""SELECT title, status, timestamp from songs """)
            print(listArray)
        else:
            if locatorColumn != "All": #No strings concatenation, no security holes
                if locatorColumn == "Title":
                    sql = """SELECT title, status, timestamp from songs where title LIKE ?"""
                elif locatorColumn == "Status":
                    sql = """SELECT title, status, timestamp from songs where status LIKE ?"""
                elif locatorColumn == "Description":
                    sql = """SELECT title, status, timestamp from songs where description LIKE ?"""
                elif locatorColumn == "Style":
                    sql = """SELECT title, status, timestamp from songs where style LIKE ?"""

                locatorItem = "%" + locatorItem + "%"
                listArray = queries(sql, (locatorItem,))
            else:
                locatorItem = "%" + locatorItem + "%"
                variables = [locatorItem, locatorItem, locatorItem, locatorItem, locatorItem]
                listArray = queries("""SELECT title, status, timestamp from songs
                where title LIKE ? OR type LIKE ? OR original_song LIKE ? OR link LIKE ?
                OR description LIKE ?""", variables)
        for item in listArray:
            title = item[0]
            status = item[1]
            timestamp = item[2]
            try:
                timestamp = datetime.strptime(timestamp, "%d/%m/%Y %H:%M")
                timestamp = timestamp.strftime("%d/%m/%Y")
            except:
                timestamp = ""

            text = "%s %s %s" % (title, status, timestamp)
            qItem = QListWidgetItem(text)
            qItem.setData(Qt.UserRole, title)
            self.songsListWidget.addItem(qItem)
        #new idea
        qItem = QListWidgetItem("New song...")
        qItem.setData(Qt.UserRole, "New song...") #otherwise that would be an error
        self.songsListWidget.addItem(qItem)
        self.songsListWidget.blockSignals(False)

    def listWidgetRightClick(self, position):
        widgetItem = self.songsListWidget.itemAt(position)
        if widgetItem != None: #quick lazy text fix
            if widgetItem.text() != "New song...":
                print(widgetItem.text())
                menu = QMenu()
                deleteAction = QAction(self.DELETE_ICON, "Delete song")
                menu.addAction(deleteAction)
                action = menu.exec(self.mapToGlobal(position)) 

                if action == deleteAction:
                    msg = QMessageBox.question(None, "Delete?", "Are you sure you want to delete this entry?")
                    if msg == QMessageBox.Yes:
                        title = widgetItem.data(Qt.UserRole)
                        queries("DELETE from songs where title = ?", (title,))
                        self.populateList()
                        self.songsListWidget.setCurrentRow(0)

    def songVariations(self):
        sql = "SELECT title from songs"
        songArray = []
        for song in queries(sql)[0]:
            songArray.append(song)
        return songArray
    def checkBoxPositionAsignment(self):
            self.y += 1
            if self.y == 4:
                self.y = 0
                self.x += 1
    def addStyle(self, text=""):
        "text = "" if comes from outside"

        self.styleEdit = QLineEdit()
        self.styleEdit.setPlaceholderText("Style")
        self.styleEdit.textChanged.connect(self.validateStyle)
        self.styleEdit.returnPressed.connect(lambda: self.addStyle(self.styleEdit.text()))

        if text != "":
            self.styleLayout.takeAt(self.styleLayout.count()-1).widget().deleteLater()

            styleCheckBox = QCheckBox()
            styleCheckBox.setText(text)
            print(text)
            self.styleLayout.addWidget(styleCheckBox, self.x, self.y)
            self.checkBoxPositionAsignment()
            print(self.durationLine.text())
        self.styleLayout.addWidget(self.styleEdit)


    def checkSong(self):
        text = self.titleEdit.text()
        sql = "SELECT title from songs where title = ?"
        if len(queries(sql, (text,))) != 0:
            self.titleEdit.setText("")
    def validateSong(self):
        pass
        #VALIDATE REG EXP

    def validateStyle(self, text):
        if "," in text:
            self.styleEdit.undo()

    def playSong(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.mediaPlayer.pause()
        else:
            self.mediaPlayer.play()

    def mediaStateChanged(self):
        if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
            self.playButton.setIcon(self.PAUSE_ICON)
        else:
            self.playButton.setIcon(self.PLAY_ICON)
    def positionChanged(self, position):
        if position != self.mediaPlayer.duration():
            self.slider.setValue(position)
    def durationChanged(self, duration):
        if duration != self.mediaPlayer.position():
            print("duration chagned")
            self.slider.setRange(0, duration)
    def playSlider(self):
        self.mediaPlayer.setPosition(self.slider.value())

    def stopSong(self):
        self.mediaPlayer.stop()

    def locateFile(self):
        self.fileSystem = QFileDialog(filter="Sound files (*.wav *.mp3 *.flac)")
        self.fileSystem.show()
        self.fileSystem.fileSelected.connect(self.fileLoaded)

    def fileLoaded(self, path):
        self.locationLine.setText(path)
        try:
            self.playlist = QMediaPlaylist()
            self.playlist.addMedia(QMediaContent(QUrl.fromLocalFile(path)))
            self.mediaPlayer.setPlaylist(self.playlist)
        except:
            print("fail")
        self.slider.setVisible(True)
        self.playButton.setVisible(True)
        self.stopButton.setVisible(True)

    def saveSong(self):
        title = self.titleEdit.text()
        status = self.statusBox.currentText()
        date = self.dateEdit.text()
        style = ""

        print(status, style)
        x = 0
        for checkBox in self.styleGroupBox.children():
            if isinstance(checkBox, QCheckBox):
                if checkBox.isChecked():
                    style += (checkBox.text()) + ","
                    x+=1
        if x != 0: style = style.rstrip(",")
        else: style = None

        duration = self.durationLine.time()
        duration = QTime(0, 0).secsTo(duration)

        project = self.projectComboBox.currentText()
        variation = self.variationLine.text()
        description = self.descriptionTextEdit.toPlainText()
        location = self.locationLine.text()

        variables = [title, status, description, location, project,\
        variation, date, style, duration]

        print("---------", variables)

        sql = """INSERT OR REPLACE into songs
        (title, status, description, location, project,
        variation_another_song, timestamp, style, duration)

        values
        (?,      ?,       ?,          ?,     ?,
         ?,                     ?,         ?,      ?)"""

        queries(sql, variables)
        self.populateList()
Пример #4
0
class ComputingGroup(QGroupBoxCollapsible):
    """
    This class is a subclass of class QGroupBox.
    """
    send_refresh_filenames = pyqtSignal(name='send_refresh_filenames')

    def __init__(self, path_prj, name_prj, send_log, title):
        super().__init__()
        self.path_prj = path_prj
        self.name_prj = name_prj
        self.send_log = send_log
        self.path_last_file_loaded = self.path_prj
        self.project_properties = load_project_properties(self.path_prj)
        self.setTitle(title)
        self.init_ui()
        self.msg2 = QMessageBox()
        self.mesh_manager_file = self.read_attribute_xml("mesh_manager_file")
        self.read_mesh_manager_file(self.mesh_manager_file)
        # process_manager
        self.process_manager = MyProcessManager("mesh_manager")

    def init_ui(self):
        # file_selection
        file_selection_label = QLabel(self.tr("Select a 2D mesh file :"))
        self.file_selection_listwidget = QListWidget()
        self.file_selection_listwidget.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.file_selection_listwidget.itemSelectionChanged.connect(
            self.names_hdf5_change)
        self.file_selection_listwidget.setVerticalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.file_selection_listwidget.verticalScrollBar().setEnabled(True)
        self.file_selection_listwidget.verticalScrollBar(
        ).valueChanged.connect(self.change_scroll_position)
        self.scrollbar = self.file_selection_listwidget.verticalScrollBar()

        mesh_manager_file = QLabel(self.tr("Mesh manager file (.txt)"))
        self.mesh_manager_filename_label = QLabel("")
        self.mesh_manager_file_select_pushbutton = QPushButton("...")
        self.mesh_manager_file_select_pushbutton.clicked.connect(
            self.select_mesh_manager_file_dialog)

        # progress_layout
        self.progress_layout = ProcessProgLayout(
            self.compute,
            send_log=self.send_log,
            process_type="mesh_manager",
            send_refresh_filenames=self.send_refresh_filenames)

        file_selection_layout = QGridLayout()
        file_selection_layout.addWidget(file_selection_label, 0, 0)
        file_selection_layout.addWidget(self.file_selection_listwidget, 1, 0)
        file_selection_layout.addWidget(self.scrollbar, 1, 1)
        file_selection_layout.setColumnStretch(0, 30)
        file_selection_layout.setColumnStretch(1, 1)

        grid_layout = QGridLayout()
        grid_layout.addWidget(mesh_manager_file, 0, 0, Qt.AlignLeft)
        grid_layout.addWidget(self.mesh_manager_filename_label, 0, 1,
                              Qt.AlignLeft)
        grid_layout.addWidget(self.mesh_manager_file_select_pushbutton, 0, 2,
                              Qt.AlignLeft)
        grid_layout.addLayout(self.progress_layout, 1, 0, 1, 3)

        general_layout = QVBoxLayout()
        general_layout.addLayout(file_selection_layout)
        general_layout.addLayout(grid_layout)

        self.setLayout(general_layout)

    def update_gui(self):
        selected_file_names = [
            selection_el.text()
            for selection_el in self.file_selection_listwidget.selectedItems()
        ]
        # computing_group
        hyd_names = get_filename_by_type_physic(
            "hydraulic", os.path.join(self.path_prj, "hdf5"))
        hab_names = get_filename_by_type_physic(
            "habitat", os.path.join(self.path_prj, "hdf5"))
        names = hyd_names + hab_names
        self.file_selection_listwidget.blockSignals(True)
        self.file_selection_listwidget.clear()
        if names:
            for name in names:
                # check
                try:
                    hdf5 = Hdf5Management(self.path_prj,
                                          name,
                                          new=False,
                                          edit=False)
                    hdf5.get_hdf5_attributes(close_file=True)
                    item_name = QListWidgetItem()
                    item_name.setText(name)
                    self.file_selection_listwidget.addItem(item_name)
                    if name in selected_file_names:
                        item_name.setSelected(True)
                    if True:  #TODO : sort files (hdf5 attributes available for HRR) .hyd, one whole profile for all units, ...
                        pass
                    else:
                        pass
                except:
                    self.send_log.emit(
                        self.
                        tr("Error: " + name +
                           " file seems to be corrupted. Delete it with HABBY or manually."
                           ))

        self.file_selection_listwidget.blockSignals(False)
        # preselection if one
        if self.file_selection_listwidget.count() == 1:
            self.file_selection_listwidget.selectAll()

    def change_scroll_position(self, index):
        self.file_selection_listwidget.verticalScrollBar().setValue(index)

    def names_hdf5_change(self):
        selection = self.file_selection_listwidget.selectedItems()
        self.progress_layout.progress_bar.setValue(0.0)
        self.progress_layout.progress_label.setText("{0:.0f}/{1:.0f}".format(
            0.0, len(selection)))
        if selection:
            self.progress_layout.run_stop_button.setEnabled(True)
        else:
            self.progress_layout.run_stop_button.setEnabled(False)

    def read_mesh_manager_file(self, mesh_manager_file):
        if os.path.exists(mesh_manager_file):
            self.mesh_manager_description, warnings_list = mesh_manager_from_file(
                mesh_manager_file)
            if warnings_list:
                for warning in warnings_list:
                    self.send_log.emit(warning)
            if self.mesh_manager_description["mesh_manager_data"] is None:
                self.send_log.emit(
                    self.tr("Error: Mesh manager file : ") +
                    os.path.basename(mesh_manager_file) +
                    self.tr(" is not valid."))
                self.progress_layout.run_stop_button.setEnabled(False)
            else:
                self.mesh_manager_filename_label.setText(
                    os.path.basename(mesh_manager_file))
                if self.file_selection_listwidget.selectedItems():
                    self.progress_layout.run_stop_button.setEnabled(True)
        else:
            self.progress_layout.run_stop_button.setEnabled(False)

        self.progress_layout.progress_bar.setValue(0.0)
        self.progress_layout.progress_label.setText("{0:.0f}/{1:.0f}".format(
            0.0, len(self.file_selection_listwidget.selectedItems())))

    def select_mesh_manager_file_dialog(self):
        self.mesh_manager_file = self.read_attribute_xml("mesh_manager_file")
        # get last path
        if self.mesh_manager_file != self.path_prj and self.mesh_manager_file != "":
            model_path = self.mesh_manager_file  # path spe
        elif self.read_attribute_xml(
                "path_last_file_loaded"
        ) != self.path_prj and self.read_attribute_xml(
                "path_last_file_loaded") != "":
            model_path = self.read_attribute_xml(
                "path_last_file_loaded")  # path last
        else:
            model_path = self.path_prj  # path proj

        filename, _ = QFileDialog.getOpenFileName(
            self, self.tr("Select a mesh manager file"), model_path,
            self.tr("Text files") + " (*.txt)")
        if filename:
            self.pathfile = filename  # source file path
            self.save_xml("mesh_manager_file")
            self.read_mesh_manager_file(filename)
            self.mesh_manager_file = self.read_attribute_xml(
                "mesh_manager_file")

    def read_attribute_xml(self, att_here):
        """
        A function to read the text of an attribute in the xml project file.

        :param att_here: the attribute name (string).
        """
        data = ''

        filename_path_pro = os.path.join(self.path_prj,
                                         self.name_prj + '.habby')
        if os.path.isfile(filename_path_pro):
            if att_here in {"path_last_file_loaded"}:
                data = load_project_properties(self.path_prj)[att_here]
            else:
                try:
                    data = load_project_properties(self.path_prj)[att_here]
                except KeyError:
                    self.save_xml("mesh_manager_file")
                    data = load_project_properties(self.path_prj)[att_here]
        else:
            pass

        return data

    def save_xml(self, attr):
        """
        A function to save the loaded data in the xml file.

        This function adds the name and the path of the newly chosen hydrological data to the xml project file. First,
        it open the xml project file (and send an error if the project is not saved, or if it cannot find the project
        file). Then, it opens the xml file and add the path and name of the file to this xml file. If the model data was
        already loaded, it adds the new name without erasing the old name IF the switch append_name is True. Otherwise,
        it erase the old name and replace it by a new name. The variable “i” has the same role than in select_file_and_show_informations_dialog.

        :param i: a int for the case where there is more than one file to load
        :param append_name: A boolean. If True, the name found will be append to the existing name in the xml file,
                instead of remplacing the old name by the new name.

        """
        filename_path_pro = os.path.join(self.path_prj,
                                         self.name_prj + '.habby')

        # save the name and the path in the xml .prj file
        if not os.path.isfile(filename_path_pro):
            self.end_log.emit(
                'Error: The project is not saved. '
                'Save the project in the General tab before saving hydrological data. \n'
            )
        else:
            # change path_last_file_loaded, model_type (path)
            self.project_properties = load_project_properties(
                self.path_prj)  # load_project_properties
            self.project_properties[
                "path_last_file_loaded"] = self.pathfile  # change value
            self.project_properties[attr] = self.pathfile  # change value
            save_project_properties(
                self.path_prj,
                self.project_properties)  # save_project_properties

    def compute(self):
        if len(self.file_selection_listwidget.selectedItems()) > 0:
            mesh_manager_description = self.mesh_manager_description
            mesh_manager_description["hdf5_name_list"] = [
                selection_el.text() for selection_el in
                self.file_selection_listwidget.selectedItems()
            ]

            # for hdf5_file in mesh_manager_description["hdf5_name_list"]:
            #     hdf5_1 = Hdf5Management(self.path_prj, hdf5_file, new=False, edit=False)
            #     hdf5_1.load_hdf5(whole_profil=False)
            #     if hdf5_1.data_2d.hvum.hdf5_and_computable_list.habs():
            #         self.msg2.setIcon(QMessageBox.Warning)
            #         self.msg2.setWindowTitle(self.tr("HSI data in ") + hdf5_1.filename[:-4] + "_MM" + hdf5_1.extension + ".")
            #         self.msg2.setText(self.tr("If computing, existing HSI data will be removed in ") + hdf5_1.filename[:-4] + "_MM" + hdf5_1.extension + ".\n"+
            #                           self.tr("Do you really want to continue computing ?"))
            #         self.msg2.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            #         res = self.msg2.exec_()
            #
            #         # cancel
            #         if res == QMessageBox.No:
            #             return
            #         if res == QMessageBox.Yes:
            #             break

            self.progress_layout.process_manager.set_mesh_manager(
                self.path_prj, mesh_manager_description,
                self.project_properties)

            # start thread
            self.progress_layout.start_process()

    def stop_compute(self):
        # stop_by_user
        self.process_manager.stop_by_user()
Пример #5
0
class VisualGroup(QGroupBoxCollapsible):
    """
    This class is a subclass of class QGroupBox.
    """

    def __init__(self, path_prj, name_prj, send_log, title):
        super().__init__()
        self.path_prj = path_prj
        self.name_prj = name_prj
        self.send_log = send_log
        self.path_last_file_loaded = self.path_prj
        self.process_manager = MyProcessManager("hs_plot")
        self.axe_mod_choosen = 1
        self.setTitle(title)
        self.init_ui()
        self.process_prog_show_input = ProcessProgShow(send_log=self.send_log,
                                                 run_function=self.plot_hs_class,
                                                 computation_pushbutton=self.input_class_plot_button)
        self.process_prog_show_area = ProcessProgShow(send_log=self.send_log,
                                                 run_function=self.plot_hs_area,
                                                 computation_pushbutton=self.result_plot_button_area)
        self.process_prog_show_volume = ProcessProgShow(send_log=self.send_log,
                                                 run_function=self.plot_hs_volume,
                                                 computation_pushbutton=self.result_plot_button_volume)

    def init_ui(self):
        # file_selection
        file_selection_label = QLabel(self.tr("HS files :"))
        self.file_selection_listwidget = QListWidget()
        self.file_selection_listwidget.itemSelectionChanged.connect(self.names_hdf5_change)
        file_selection_layout = QVBoxLayout()
        file_selection_layout.addWidget(file_selection_label)
        file_selection_layout.addWidget(self.file_selection_listwidget)

        # reach
        reach_label = QLabel(self.tr('reach(s)'))
        self.reach_QListWidget = QListWidget()
        self.reach_QListWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.reach_QListWidget.itemSelectionChanged.connect(self.reach_hdf5_change)
        reach_layout = QVBoxLayout()
        reach_layout.addWidget(reach_label)
        reach_layout.addWidget(self.reach_QListWidget)

        # units
        units_label = QLabel(self.tr('unit(s)'))
        self.units_QListWidget = QListWidget()
        self.units_QListWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.units_QListWidget.itemSelectionChanged.connect(self.unit_hdf5_change)
        units_layout = QVBoxLayout()
        units_layout.addWidget(units_label)
        units_layout.addWidget(self.units_QListWidget)

        # axe
        self.axe_mod_choosen = load_specific_properties(self.path_prj, ["hs_axe_mod"])[0]

        axe_label = QLabel(self.tr("Axe orientation :"))
        self.axe_mod_1_radio = QRadioButton()
        if self.axe_mod_choosen == 1:
            self.axe_mod_1_radio.setChecked(True)
        self.axe_mod_1_radio.setIcon(QIcon(r"file_dep/axe_mod_1.png"))
        self.axe_mod_1_radio.setIconSize(QSize(75, 75))
        self.axe_mod_1_radio.clicked.connect(self.change_axe_mod)

        self.axe_mod_2_radio = QRadioButton()
        if self.axe_mod_choosen == 2:
            self.axe_mod_2_radio.setChecked(True)
        self.axe_mod_2_radio.setIcon(QIcon(r"file_dep/axe_mod_2.png"))
        self.axe_mod_2_radio.setIconSize(QSize(75, 75))
        self.axe_mod_2_radio.clicked.connect(self.change_axe_mod)

        self.axe_mod_3_radio = QRadioButton()
        if self.axe_mod_choosen == 3:
            self.axe_mod_3_radio.setChecked(True)
        self.axe_mod_3_radio.setIcon(QIcon(r"file_dep/axe_mod_3.png"))
        self.axe_mod_3_radio.setIconSize(QSize(75, 75))
        self.axe_mod_3_radio.clicked.connect(self.change_axe_mod)

        axe_mod_layout = QHBoxLayout()
        axe_mod_layout.addWidget(self.axe_mod_1_radio)
        axe_mod_layout.addWidget(self.axe_mod_2_radio)
        axe_mod_layout.addWidget(self.axe_mod_3_radio)
        axe_layout = QVBoxLayout()
        axe_layout.addWidget(axe_label)
        axe_layout.addLayout(axe_mod_layout)
        axe_layout.addStretch()
        selection_layout = QHBoxLayout()
        selection_layout.addLayout(file_selection_layout)
        selection_layout.addLayout(reach_layout)
        selection_layout.addLayout(units_layout)
        selection_layout.addLayout(axe_layout)

        # input_class
        input_class_label = QLabel(self.tr("Input class :"))
        input_class_h_label = QLabel(self.tr("h (m)"))
        self.input_class_h_lineedit = QLineEdit("")
        input_class_v_label = QLabel(self.tr("v (m)"))
        self.input_class_v_lineedit = QLineEdit("")
        self.input_class_plot_button = QPushButton(self.tr("Show input"))
        self.input_class_plot_button.clicked.connect(self.plot_hs_class)
        change_button_color(self.input_class_plot_button, "#47B5E6")
        self.input_class_plot_button.setEnabled(False)
        input_class_layout = QGridLayout()
        input_class_layout.addWidget(input_class_label, 0, 0, 1, 2)
        input_class_layout.addWidget(input_class_h_label, 1, 0)
        input_class_layout.addWidget(input_class_v_label, 2, 0)
        input_class_layout.addWidget(self.input_class_h_lineedit, 1, 1)
        input_class_layout.addWidget(self.input_class_v_lineedit, 2, 1)
        input_class_layout.addWidget(self.input_class_plot_button, 1, 2, 2, 1)  # from row, from column, nb row, nb column

        # result
        result_label = QLabel(self.tr("Result :"))
        self.result_tableview = QTableView()
        self.result_tableview.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        self.result_tableview.verticalHeader().setVisible(False)
        self.result_tableview.horizontalHeader().setVisible(False)
        self.result_plot_button_area = QPushButton(self.tr("Show area"))
        self.result_plot_button_area.clicked.connect(self.plot_hs_area)
        self.result_plot_button_area.setEnabled(False)
        change_button_color(self.result_plot_button_area, "#47B5E6")
        self.result_plot_button_volume = QPushButton(self.tr("Show volume"))
        self.result_plot_button_volume.clicked.connect(self.plot_hs_volume)
        self.result_plot_button_volume.setEnabled(False)
        change_button_color(self.result_plot_button_volume, "#47B5E6")
        pushbutton_layout = QVBoxLayout()
        pushbutton_layout.addWidget(self.result_plot_button_area)
        pushbutton_layout.addWidget(self.result_plot_button_volume)
        result_layout = QGridLayout()
        result_layout.addWidget(result_label, 0, 0)
        result_layout.addWidget(self.result_tableview, 1, 0, 2, 1)
        result_layout.addLayout(pushbutton_layout, 1, 1)
        self.input_result_group = QGroupBox()
        input_result_layout = QVBoxLayout()
        input_result_layout.addLayout(input_class_layout)
        input_result_layout.addLayout(result_layout)
        self.input_result_group.setLayout(input_result_layout)
        self.input_result_group.hide()

        general_layout = QVBoxLayout()
        general_layout.addLayout(selection_layout)
        general_layout.addWidget(self.input_result_group)

        self.setLayout(general_layout)

    def update_gui(self):
        hs_names = get_filename_hs(os.path.join(self.path_prj, "hdf5"))
        self.file_selection_listwidget.blockSignals(True)
        self.file_selection_listwidget.clear()
        if hs_names:
            self.file_selection_listwidget.addItems(hs_names)
        self.file_selection_listwidget.blockSignals(False)

    def change_axe_mod(self):
        if self.axe_mod_1_radio.isChecked():
            self.axe_mod_choosen = 1
        elif self.axe_mod_2_radio.isChecked():
            self.axe_mod_choosen = 2
        elif self.axe_mod_3_radio.isChecked():
            self.axe_mod_choosen = 3
        change_specific_properties(self.path_prj, ["hs_axe_mod"], [self.axe_mod_choosen])

    def names_hdf5_change(self):
        self.reach_QListWidget.clear()
        self.units_QListWidget.clear()
        selection = self.file_selection_listwidget.selectedItems()
        if selection:
            # read
            hdf5name = selection[0].text()
            hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False)
            hdf5.get_hdf5_attributes(close_file=True)
            # check reach
            self.reach_QListWidget.addItems(hdf5.data_2d.reach_list)

            self.input_class_h_lineedit.setText(", ".join(list(map(str, hdf5.hs_input_class[0]))))
            self.input_class_v_lineedit.setText(", ".join(list(map(str, hdf5.hs_input_class[1]))))

            self.input_class_plot_button.setEnabled(True)

            self.toggle_group(False)
            self.input_result_group.show()
            self.toggle_group(True)

        else:
            self.input_result_group.hide()

    def reach_hdf5_change(self):
        selection_file = self.file_selection_listwidget.selectedItems()
        selection_reach = self.reach_QListWidget.selectedItems()
        self.units_QListWidget.clear()
        # one file selected
        if len(selection_reach) == 1:
            hdf5name = selection_file[0].text()

            # create hdf5 class
            hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False)
            hdf5.get_hdf5_attributes(close_file=True)

            # add units
            for item_text in hdf5.data_2d.unit_list[self.reach_QListWidget.currentRow()]:
                item = QListWidgetItem(item_text)
                item.setTextAlignment(Qt.AlignRight)
                self.units_QListWidget.addItem(item)

        if len(selection_reach) > 1:
            # add units
            item = QListWidgetItem("all units")
            item.setTextAlignment(Qt.AlignRight)
            self.units_QListWidget.addItem(item)
            self.units_QListWidget.selectAll()

    def unit_hdf5_change(self):
        selection_unit = self.units_QListWidget.selectedItems()
        # one file selected
        if len(selection_unit) > 0:
            hdf5name = self.file_selection_listwidget.selectedItems()[0].text()

            # create hdf5 class
            hdf5 = Hdf5Management(self.path_prj, hdf5name, new=False, edit=False)
            hdf5.load_hydrosignature()
            hdf5.close_file()

            if len(selection_unit) == 1 and selection_unit[0].text() == "all units":
                # get hs data
                hdf5.data_2d.get_hs_summary_data([element.row() for element in self.reach_QListWidget.selectedIndexes()],
                                                 list(range(hdf5.nb_unit)))
            else:
                # get hs data
                hdf5.data_2d.get_hs_summary_data([element.row() for element in self.reach_QListWidget.selectedIndexes()],
                                                 [element.row() for element in self.units_QListWidget.selectedIndexes()])

            # table
            mytablemodel = MyTableModel(hdf5.data_2d.hs_summary_data)
            self.result_tableview.setModel(mytablemodel)  # set model
            self.result_plot_button_area.setEnabled(True)
            self.result_plot_button_volume.setEnabled(True)
        else:
            mytablemodel = MyTableModel(["", ""])
            self.result_tableview.setModel(mytablemodel)  # set model
            self.result_plot_button_area.setEnabled(False)
            self.result_plot_button_volume.setEnabled(False)

    def plot_hs_class(self):
        plot_attr = lambda: None

        plot_attr.nb_plot = 1
        plot_attr.axe_mod_choosen = self.axe_mod_choosen
        plot_attr.hs_plot_type = "input_class"

        # process_manager
        self.process_manager.set_plot_hdf5_mode(self.path_prj,
                                                [self.file_selection_listwidget.selectedItems()[0].text()],
                                                plot_attr,
                                                load_project_properties(self.path_prj))

        # process_prog_show
        self.process_prog_show_input.start_show_prog(self.process_manager)

    def plot_hs_area(self):
        plot_attr = lambda: None

        plot_attr.axe_mod_choosen = self.axe_mod_choosen
        plot_attr.hs_plot_type = "area"
        plot_attr.reach = [element.row() for element in self.reach_QListWidget.selectedIndexes()]
        plot_attr.units = [element.row() for element in self.units_QListWidget.selectedIndexes()]
        plot_attr.nb_plot = len(plot_attr.units)

        # process_manager
        self.process_manager.set_plot_hdf5_mode(self.path_prj,
                                                [self.file_selection_listwidget.selectedItems()[0].text()],
                                                plot_attr,
                                                load_project_properties(self.path_prj))

        # process_prog_show
        self.process_prog_show_area.start_show_prog(self.process_manager)

    def plot_hs_volume(self):
        plot_attr = lambda: None

        plot_attr.axe_mod_choosen = self.axe_mod_choosen
        plot_attr.hs_plot_type = "volume"
        plot_attr.reach = [element.row() for element in self.reach_QListWidget.selectedIndexes()]
        plot_attr.units = [element.row() for element in self.units_QListWidget.selectedIndexes()]
        plot_attr.nb_plot = len(plot_attr.units)

        # process_manager
        self.process_manager.set_plot_hdf5_mode(self.path_prj,
                                                [self.file_selection_listwidget.selectedItems()[0].text()],
                                                plot_attr,
                                                load_project_properties(self.path_prj))

        # process_prog_show
        self.process_prog_show_volume.start_show_prog(self.process_manager)
Пример #6
0
class ComputingGroup(QGroupBoxCollapsible):
    """
    This class is a subclass of class QGroupBox.
    """
    send_refresh_filenames = pyqtSignal(name='send_refresh_filenames')

    def __init__(self, path_prj, name_prj, send_log, title):
        super().__init__()
        self.path_prj = path_prj
        self.name_prj = name_prj
        self.send_log = send_log
        self.path_last_file_loaded = self.path_prj
        self.classhv = None
        self.project_properties = load_project_properties(self.path_prj)
        self.setTitle(title)
        self.init_ui()
        self.input_class_file_info = self.read_attribute_xml("HS_input_class")
        self.read_input_class(os.path.join(self.input_class_file_info["path"], self.input_class_file_info["file"]))
        # process_manager
        self.process_manager = MyProcessManager("hs")

    def init_ui(self):
        # file_selection
        file_selection_label = QLabel(self.tr("Select a 2D mesh file :"))
        self.file_selection_listwidget = QListWidget()
        self.file_selection_listwidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.file_selection_listwidget.itemSelectionChanged.connect(self.names_hdf5_change)
        self.file_selection_listwidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.file_selection_listwidget.verticalScrollBar().setEnabled(True)
        self.file_selection_listwidget.verticalScrollBar().valueChanged.connect(self.change_scroll_position)
        self.scrollbar = self.file_selection_listwidget.verticalScrollBar()
        file_computed_label = QLabel(self.tr("Computed ?"))
        self.hs_computed_listwidget = QListWidget()
        self.hs_computed_listwidget.setEnabled(False)
        self.hs_computed_listwidget.setFlow(QListView.TopToBottom)
        self.hs_computed_listwidget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.hs_computed_listwidget.verticalScrollBar().setEnabled(True)
        self.hs_computed_listwidget.verticalScrollBar().valueChanged.connect(self.change_scroll_position)

        file_selection_layout = QGridLayout()
        file_selection_layout.addWidget(file_selection_label, 0, 0)
        file_selection_layout.addWidget(self.file_selection_listwidget, 1, 0)
        file_selection_layout.addWidget(file_computed_label, 0, 1)
        file_selection_layout.addWidget(self.hs_computed_listwidget, 1, 1)
        file_selection_layout.addWidget(self.scrollbar, 1, 2)
        file_selection_layout.setColumnStretch(0, 30)
        file_selection_layout.setColumnStretch(1, 1)

        input_class_label = QLabel(self.tr("Input class (.txt)"))
        self.input_class_filename = QLabel("")
        self.input_class_pushbutton = QPushButton("...")
        self.input_class_pushbutton.clicked.connect(self.select_input_class_dialog)
        hs_export_txt_label = QLabel(self.tr("Export results (.txt)"))
        self.hs_export_txt_checkbox = QCheckBox()
        self.hs_export_txt_checkbox.setChecked(True)
        hs_export_mesh_label = QLabel(self.tr("Export mesh results (.hyd or .hab)"))
        self.hs_export_mesh_checkbox = QCheckBox()

        """ progress layout """
        # progress_layout
        self.progress_layout = ProcessProgLayout(self.compute,
                                                 send_log=self.send_log,
                                                 process_type="hs",
                                                 send_refresh_filenames=self.send_refresh_filenames)

        grid_layout = QGridLayout()
        grid_layout.addWidget(input_class_label, 2, 0, Qt.AlignLeft)
        grid_layout.addWidget(self.input_class_filename, 2, 1, Qt.AlignLeft)
        grid_layout.addWidget(self.input_class_pushbutton, 2, 2, Qt.AlignLeft)
        grid_layout.addWidget(hs_export_txt_label, 3, 0, Qt.AlignLeft)
        grid_layout.addWidget(self.hs_export_txt_checkbox, 3, 1, Qt.AlignLeft)
        grid_layout.addWidget(hs_export_mesh_label, 4, 0, Qt.AlignLeft)
        grid_layout.addWidget(self.hs_export_mesh_checkbox, 4, 1, Qt.AlignLeft)
        grid_layout.addLayout(self.progress_layout, 5, 0, 1, 3)

        grid_layout.setColumnStretch(0, 2)
        grid_layout.setColumnStretch(1, 1)
        grid_layout.setColumnStretch(2, 1)
        grid_layout.setAlignment(Qt.AlignRight)

        general_layout = QVBoxLayout()
        general_layout.addLayout(file_selection_layout)
        general_layout.addLayout(grid_layout)

        self.setLayout(general_layout)

    def update_gui(self):
        selected_file_names = [selection_el.text() for selection_el in self.file_selection_listwidget.selectedItems()]
        # computing_group
        hyd_names = get_filename_by_type_physic("hydraulic", os.path.join(self.path_prj, "hdf5"))
        hab_names = get_filename_by_type_physic("habitat", os.path.join(self.path_prj, "hdf5"))
        names = hyd_names + hab_names
        self.file_selection_listwidget.blockSignals(True)
        self.file_selection_listwidget.clear()
        self.hs_computed_listwidget.blockSignals(True)
        self.hs_computed_listwidget.clear()
        if names:
            for name in names:
                # filename
                item_name = QListWidgetItem()
                item_name.setText(name)
                self.file_selection_listwidget.addItem(item_name)
                if name in selected_file_names:
                    item_name.setSelected(True)
                # check
                item = QListWidgetItem()
                item.setText("")
                item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
                try:
                    hdf5 = Hdf5Management(self.path_prj, name, new=False, edit=False)
                    hdf5.get_hdf5_attributes(close_file=True)
                    if hdf5.hs_calculated:
                        item.setCheckState(Qt.Checked)
                    else:
                        item.setCheckState(Qt.Unchecked)
                except:
                    self.send_log.emit(self.tr("Error: " + name + " file seems to be corrupted. Delete it with HABBY or manually."))
                self.hs_computed_listwidget.addItem(item)

                item.setTextAlignment(Qt.AlignCenter)

        self.file_selection_listwidget.blockSignals(False)
        self.hs_computed_listwidget.blockSignals(False)
        # preselection if one
        if self.file_selection_listwidget.count() == 1:
            self.file_selection_listwidget.selectAll()

    def change_scroll_position(self, index):
        self.file_selection_listwidget.verticalScrollBar().setValue(index)
        self.hs_computed_listwidget.verticalScrollBar().setValue(index)

    def read_input_class(self, input_class_file):
        if os.path.exists(input_class_file):
            self.classhv, warnings_list = hydrosignature_mod.hydraulic_class_from_file(input_class_file)
            if warnings_list:
                for warning in warnings_list:
                    self.send_log.emit(warning)
            if self.classhv is None:
                self.send_log.emit(self.tr("Error: Input class file : ") + os.path.basename(input_class_file) + self.tr(" is not valid."))
                self.progress_layout.run_stop_button.setEnabled(False)
            else:
                self.input_class_filename.setText(os.path.basename(input_class_file))
                if self.file_selection_listwidget.selectedItems():
                    self.progress_layout.run_stop_button.setEnabled(True)
        else:
            self.progress_layout.run_stop_button.setEnabled(False)

        self.progress_layout.progress_bar.setValue(0.0)
        self.progress_layout.progress_label.setText(
            "{0:.0f}/{1:.0f}".format(0.0, len(self.file_selection_listwidget.selectedItems())))

    def names_hdf5_change(self):
        selection = self.file_selection_listwidget.selectedItems()
        self.progress_layout.progress_bar.setValue(0.0)
        self.progress_layout.progress_label.setText(
            "{0:.0f}/{1:.0f}".format(0.0, len(selection)))
        if selection:
            # enable run button
            if self.input_class_filename.text():
                self.progress_layout.run_stop_button.setEnabled(True)
            else:
                self.progress_layout.run_stop_button.setEnabled(False)
        else:
            self.progress_layout.run_stop_button.setEnabled(False)

    def select_input_class_dialog(self):
        self.input_class_file_info = self.read_attribute_xml("HS_input_class")
        # get last path
        if self.input_class_file_info["path"] != self.path_prj and self.input_class_file_info["path"] != "":
            model_path = self.input_class_file_info["path"]  # path spe
        elif self.read_attribute_xml("path_last_file_loaded") != self.path_prj and self.read_attribute_xml("path_last_file_loaded") != "":
            model_path = self.read_attribute_xml("path_last_file_loaded")  # path last
        else:
            model_path = self.path_prj  # path proj

        filename, _ = QFileDialog.getOpenFileName(self, self.tr("Select hydraulic class file"),
                                                  model_path, self.tr("Text files") + " (*.txt)")
        if filename:
            self.pathfile = os.path.dirname(filename)  # source file path
            self.namefile = os.path.basename(filename)  # source file name
            self.save_xml("HS_input_class")
            self.read_input_class(filename)
            self.input_class_file_info = self.read_attribute_xml("HS_input_class")

    def read_attribute_xml(self, att_here):
        """
        A function to read the text of an attribute in the xml project file.

        :param att_here: the attribute name (string).
        """
        data = ''

        filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby')
        if os.path.isfile(filename_path_pro):
            if att_here in {"path_last_file_loaded", "HS_input_class"}:
                data = load_project_properties(self.path_prj)[att_here]
            else:
                data = load_project_properties(self.path_prj)[att_here]["path"]
        else:
            pass

        return data

    def save_xml(self, attr):
        """
        A function to save the loaded data in the xml file.

        This function adds the name and the path of the newly chosen hydrological data to the xml project file. First,
        it open the xml project file (and send an error if the project is not saved, or if it cannot find the project
        file). Then, it opens the xml file and add the path and name of the file to this xml file. If the model data was
        already loaded, it adds the new name without erasing the old name IF the switch append_name is True. Otherwise,
        it erase the old name and replace it by a new name. The variable “i” has the same role than in select_file_and_show_informations_dialog.

        :param i: a int for the case where there is more than one file to load
        :param append_name: A boolean. If True, the name found will be append to the existing name in the xml file,
                instead of remplacing the old name by the new name.

        """
        filename_path_pro = os.path.join(self.path_prj, self.name_prj + '.habby')

        # save the name and the path in the xml .prj file
        if not os.path.isfile(filename_path_pro):
            self.end_log.emit('Error: The project is not saved. '
                              'Save the project in the General tab before saving hydrological data. \n')
        else:
            # change path_last_file_loaded, model_type (path)
            self.project_properties = load_project_properties(self.path_prj)  # load_project_properties
            self.project_properties["path_last_file_loaded"] = self.pathfile  # change value
            self.project_properties[attr]["file"] = self.namefile  # change value
            self.project_properties[attr]["path"] = self.pathfile  # change value
            save_project_properties(self.path_prj, self.project_properties)  # save_project_properties

    def compute(self):
        if len(self.file_selection_listwidget.selectedItems()) > 0:
            hydrosignature_description = dict(hs_export_mesh=self.hs_export_mesh_checkbox.isChecked(),
                                              hdf5_name_list=[selection_el.text() for selection_el in
                                                              self.file_selection_listwidget.selectedItems()],
                                              hs_export_txt=self.hs_export_txt_checkbox.isChecked(),
                                              classhv_input_class_file_info=self.input_class_file_info,
                                              classhv=self.classhv)

            self.progress_layout.process_manager.set_hs_hdf5_mode(self.path_prj,
                                                                  hydrosignature_description,
                                                                  self.project_properties)

            # start thread
            self.progress_layout.start_process()

    def stop_compute(self):
        # stop_by_user
        self.process_manager.stop_by_user()
Пример #7
0
class PopupDataset(QWidget):

    def __init__(self, parent, top: Category):
        super().__init__(parent)
        self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
        self.setWindowTitle("Datasets")
        datasets = {}
        top.get_datasets(datasets)
        self.__datasets = datasets
        self.__cur_data = None
        _content = QGridLayout(self)
        self._list = QListWidget(self)
        self._list.addItems(datasets)
        self._list.blockSignals(True)
        self._list.currentItemChanged.connect(self.__changed_dataset)
        self._list.blockSignals(False)
        _content.addWidget(self._list, 0, 0, 4, 2)
        self._add = QPushButton("Add", self)
        self._add.setToolTip("")
        _content.addWidget(self._add, 4, 0)
        self._new = QPushButton("New", self)
        self._new.setToolTip("If the dataset if private or public")
        _content.addWidget(self._new, 4, 1)
        self._status = GDropbox("status", self, Status)
        self._status.setToolTip("")
        self._status.setFixedWidth(120)
        _content.addWidget(self._status, 0, 2)
        self._name = GField("name", self, str)
        self._name.setToolTip("Name of the dataset")
        _content.addWidget(self._name, 0, 3)
        self._ctype = GField("ctype", self, str)
        self._ctype.setToolTip("")
        _content.addWidget(self._ctype, 0, 4, 1, 2)
        self._dist = GDropbox("distribution", self, Distribution)
        self._dist.setToolTip("How the values are distributed in the dataset")
        self._dist.setFixedWidth(120)
        _content.addWidget(self._dist, 1, 2)
        self._min = GField("minimum", self, float)
        self._min.setToolTip("Minimum value in the dataset")
        _content.addWidget(self._min, 1, 3)
        self._max = GField("maximum", self, float)
        self._max.setToolTip("Maximum value in the dataset")
        _content.addWidget(self._max, 1, 4)
        self._dec = GField("decimals", self, int)
        self._dec.setToolTip("Number of decimals used in the dataset items")
        _content.addWidget(self._dec, 1, 5)
        self._items = GList("items", self)
        self._items.setToolTip("Dataset items")
        self._items.setFixedWidth(110)
        _content.addWidget(self._items, 2, 2, 3, 1)
        self._classes = QListWidget(self)
        self._classes.setToolTip("Instances that uses the current dataset")
        _content.addWidget(self._classes, 2, 3, 2, 3)
        self._key = QLineEdit(self)
        self._key.setToolTip("Item that will be updated (key value)")
        _content.addWidget(self._key, 4, 3)
        self._value = QLineEdit(self)
        self._value.setToolTip("Value to be used in the dataset's item update")
        _content.addWidget(self._value, 4, 4)
        self._update = QPushButton("Update", self)
        self._update.setToolTip("Update one item in the dataset using the "
                                "values provided in the field on the left")
        self._update.clicked.connect(self.__update_items)
        _content.addWidget(self._update, 4, 5)
        self.setGeometry(100, 100, 600, 400)

    def __changed_dataset(self, current, _):
        self.__cur_data, classes = self.__datasets[current.text()]
        self._status.from_obj(self.__cur_data)
        self._name.from_obj(self.__cur_data)
        self._ctype.from_obj(self.__cur_data)
        self._dec.from_obj(self.__cur_data)
        self._dist.from_obj(self.__cur_data)
        self._min .from_obj(self.__cur_data)
        self._max.from_obj(self.__cur_data)
        self._items.from_obj(self.__cur_data)
        self._classes.clear()
        for _cls in classes:
            self._classes.addItem(str(_cls))

    @action_handler
    def __update_items(self, _):
        key = int(self._key.text())
        value = float(self._value.text())
        self.__cur_data.items[key] = value
        self._items.from_obj(self.__cur_data)

    def closeEvent(self, _):
        self.parent().is_open_dataset = False
Пример #8
0
class _HistoryDialog:

    record_label = "Save..."
    execute_label = "Execute"

    def __init__(self, controller, typed_only):
        # make dialog hidden initially
        self.controller = controller
        self.typed_only = typed_only

        self.window = controller.tool_window.create_child_window(
            "Command History", close_destroys=False)
        self.window.fill_context_menu = self.fill_context_menu

        parent = self.window.ui_area
        from PyQt5.QtWidgets import QListWidget, QVBoxLayout, QFrame, QHBoxLayout, QPushButton, QLabel
        self.listbox = QListWidget(parent)
        self.listbox.setSelectionMode(QListWidget.ExtendedSelection)
        self.listbox.itemSelectionChanged.connect(self.select)
        main_layout = QVBoxLayout(parent)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.addWidget(self.listbox)
        num_cmd_frame = QFrame(parent)
        main_layout.addWidget(num_cmd_frame)
        num_cmd_layout = QHBoxLayout(num_cmd_frame)
        num_cmd_layout.setContentsMargins(0, 0, 0, 0)
        remem_label = QLabel("Remember")
        from PyQt5.QtCore import Qt
        remem_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        num_cmd_layout.addWidget(remem_label, 1)
        from PyQt5.QtWidgets import QSpinBox, QSizePolicy

        class ShorterQSpinBox(QSpinBox):
            max_val = 1000000

            def textFromValue(self, val):
                # kludge to make the damn entry field shorter
                if val == self.max_val:
                    return "1 mil"
                return str(val)

        spin_box = ShorterQSpinBox()
        spin_box.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        spin_box.setRange(100, spin_box.max_val)
        spin_box.setSingleStep(100)
        spin_box.setValue(controller.settings.num_remembered)
        spin_box.valueChanged.connect(self._num_remembered_changed)
        num_cmd_layout.addWidget(spin_box, 0)
        num_cmd_layout.addWidget(QLabel("commands"), 1)
        num_cmd_frame.setLayout(num_cmd_layout)
        button_frame = QFrame(parent)
        main_layout.addWidget(button_frame)
        button_layout = QHBoxLayout(button_frame)
        button_layout.setContentsMargins(0, 0, 0, 0)
        for but_name in [
                self.record_label, self.execute_label, "Delete", "Copy", "Help"
        ]:
            but = QPushButton(but_name, button_frame)
            but.setAutoDefault(False)
            but.clicked.connect(
                lambda arg, txt=but_name: self.button_clicked(txt))
            button_layout.addWidget(but)
        button_frame.setLayout(button_layout)
        self.window.manage(placement=None, initially_hidden=True)
        from chimerax.core.history import FIFOHistory
        self._history = FIFOHistory(controller.settings.num_remembered,
                                    controller.session, "commands")
        self._record_dialog = None
        self._search_cache = (False, None)

    def add(self, item, *, typed=False):
        if len(self._history) >= self.controller.settings.num_remembered:
            if not self.typed_only or self._history[0][1]:
                self.listbox.takeItem(0)
        if typed or not self.typed_only:
            self.listbox.addItem(item)
        self._history.enqueue((item, typed))
        # 'if typed:' to avoid clearing any partially entered command text
        if typed:
            self.listbox.clearSelection()
            self.listbox.setCurrentRow(len(self.history()) - 1)
            self.update_list()

    def button_clicked(self, label):
        session = self.controller.session
        if label == self.record_label:
            from chimerax.ui.open_save import SaveDialog
            if self._record_dialog is None:
                fmt = session.data_formats["ChimeraX commands"]
                self._record_dialog = dlg = SaveDialog(session,
                                                       self.window.ui_area,
                                                       "Save Commands",
                                                       data_formats=[fmt])
                from PyQt5.QtWidgets import QFrame, QLabel, QHBoxLayout, QVBoxLayout, QComboBox
                from PyQt5.QtWidgets import QCheckBox
                from PyQt5.QtCore import Qt
                options_frame = dlg.custom_area
                options_layout = QVBoxLayout(options_frame)
                options_frame.setLayout(options_layout)
                amount_frame = QFrame(options_frame)
                options_layout.addWidget(amount_frame, Qt.AlignCenter)
                amount_layout = QHBoxLayout(amount_frame)
                amount_layout.addWidget(QLabel("Save", amount_frame))
                self.save_amount_widget = saw = QComboBox(amount_frame)
                saw.addItems(["all", "selected"])
                amount_layout.addWidget(saw)
                amount_layout.addWidget(QLabel("commands", amount_frame))
                amount_frame.setLayout(amount_layout)
                self.append_checkbox = QCheckBox("Append to file",
                                                 options_frame)
                self.append_checkbox.stateChanged.connect(self.append_changed)
                options_layout.addWidget(self.append_checkbox, Qt.AlignCenter)
                self.overwrite_disclaimer = disclaimer = QLabel(
                    "<small><i>(ignore overwrite warning)</i></small>",
                    options_frame)
                options_layout.addWidget(disclaimer, Qt.AlignCenter)
                disclaimer.hide()
            else:
                dlg = self._record_dialog
            if not dlg.exec():
                return
            path = dlg.selectedFiles()[0]
            if not path:
                from chimerax.core.errors import UserError
                raise UserError("No file specified for saving command history")
            if self.save_amount_widget.currentText() == "all":
                cmds = [cmd for cmd in self.history()]
            else:
                # listbox.selectedItems() may not be in order, so...
                items = [
                    self.listbox.item(i) for i in range(self.listbox.count())
                    if self.listbox.item(i).isSelected()
                ]
                cmds = [item.text() for item in items]
            from chimerax.io import open_output
            f = open_output(path,
                            encoding='utf-8',
                            append=self.append_checkbox.isChecked())
            for cmd in cmds:
                print(cmd, file=f)
            f.close()
            return
        if label == self.execute_label:
            for item in self.listbox.selectedItems():
                self.controller.cmd_replace(item.text())
                self.controller.execute()
            return
        if label == "Delete":
            retain = []
            listbox_index = 0
            for h_item in self._history:
                if self.typed_only and not h_item[1]:
                    retain.append(h_item)
                    continue
                if not self.listbox.item(listbox_index).isSelected():
                    # not selected for deletion
                    retain.append(h_item)
                listbox_index += 1
            self._history.replace(retain)
            self.populate()
            return
        if label == "Copy":
            clipboard = session.ui.clipboard()
            clipboard.setText("\n".join(
                [item.text() for item in self.listbox.selectedItems()]))
            return
        if label == "Help":
            from chimerax.core.commands import run
            run(session, 'help help:user/tools/cli.html#history')
            return

    def down(self, shifted):
        sels = self.listbox.selectedIndexes()
        if len(sels) != 1:
            self._search_cache = (False, None)
            return
        sel = sels[0].row()
        orig_text = self.controller.text.currentText()
        match_against = None
        if shifted:
            was_searching, prev_search = self._search_cache
            if was_searching:
                match_against = prev_search
            else:
                words = orig_text.strip().split()
                if words:
                    match_against = words[0]
                    self._search_cache = (True, match_against)
                else:
                    self._search_cache = (False, None)
        else:
            self._search_cache = (False, None)
        if match_against:
            last = self.listbox.count() - 1
            while sel < last:
                if self.listbox.item(sel + 1).text().startswith(match_against):
                    break
                sel += 1
        if sel == self.listbox.count() - 1:
            return
        self.listbox.clearSelection()
        self.listbox.setCurrentRow(sel + 1)
        new_text = self.listbox.item(sel + 1).text()
        self.controller.cmd_replace(new_text)
        if orig_text == new_text:
            self.down(shifted)

    def fill_context_menu(self, menu, x, y):
        # avoid having actions destroyed when this routine returns
        # by stowing a reference in the menu itself
        from PyQt5.QtWidgets import QAction
        filter_action = QAction("Typed commands only", menu)
        filter_action.setCheckable(True)
        filter_action.setChecked(self.controller.settings.typed_only)
        filter_action.toggled.connect(
            lambda arg, f=self.controller._set_typed_only: f(arg))
        menu.addAction(filter_action)

    def on_append_change(self, event):
        self.overwrite_disclaimer.Show(self.save_append_CheckBox.Value)

    def append_changed(self, append):
        if append:
            self.overwrite_disclaimer.show()
        else:
            self.overwrite_disclaimer.hide()

    def on_listbox(self, event):
        self.select()

    def populate(self):
        self.listbox.clear()
        history = self.history()
        self.listbox.addItems([cmd for cmd in history])
        self.listbox.setCurrentRow(len(history) - 1)
        self.update_list()
        self.select()
        self.controller.text.lineEdit().setFocus()
        self.controller.text.lineEdit().selectAll()
        cursels = self.listbox.scrollToBottom()

    def search_reset(self):
        searching, target = self._search_cache
        if searching:
            self._search_cache = (False, None)
            self.listbox.blockSignals(True)
            self.listbox.clearSelection()
            self.listbox.setCurrentRow(self.listbox.count() - 1)
            self.listbox.blockSignals(False)

    def select(self):
        sels = self.listbox.selectedItems()
        if len(sels) != 1:
            return
        self.controller.cmd_replace(sels[0].text())

    def up(self, shifted):
        sels = self.listbox.selectedIndexes()
        if len(sels) != 1:
            self._search_cache = (False, None)
            return
        sel = sels[0].row()
        orig_text = self.controller.text.currentText()
        match_against = None
        if shifted:
            was_searching, prev_search = self._search_cache
            if was_searching:
                match_against = prev_search
            else:
                words = orig_text.strip().split()
                if words:
                    match_against = words[0]
                    self._search_cache = (True, match_against)
                else:
                    self._search_cache = (False, None)
        else:
            self._search_cache = (False, None)
        if match_against:
            while sel > 0:
                if self.listbox.item(sel - 1).text().startswith(match_against):
                    break
                sel -= 1
        if sel == 0:
            return
        self.listbox.clearSelection()
        self.listbox.setCurrentRow(sel - 1)
        new_text = self.listbox.item(sel - 1).text()
        self.controller.cmd_replace(new_text)
        if orig_text == new_text:
            self.up(shifted)

    def update_list(self):
        c = self.controller
        last8 = list(reversed(self.history()[-8:]))
        # without blocking signals, if the command list is empty then
        # "Command History" (the first entry) will execute...
        c.text.blockSignals(True)
        c.text.clear()
        c.text.addItems(last8 + [c.show_history_label, c.compact_label])
        if not last8:
            c.text.lineEdit().setText("")
        c.text.blockSignals(False)

    def history(self):
        if self.typed_only:
            return [h[0] for h in self._history if h[1]]
        return [h[0] for h in self._history]

    def set_typed_only(self, typed_only):
        self.typed_only = typed_only
        self.populate()

    def _num_remembered_changed(self, new_hist_len):
        if len(self._history) > new_hist_len:
            self._history.replace(self._history[-new_hist_len:])
            self.populate()
        self.controller.settings.num_remembered = new_hist_len
Пример #9
0
class ComputingGroup(QGroupBoxCollapsible):
    """
    This class is a subclass of class QGroupBox.
    """
    send_refresh_filenames = pyqtSignal(name='send_refresh_filenames')

    def __init__(self, path_prj, name_prj, send_log, title):
        super().__init__()
        self.path_prj = path_prj
        self.name_prj = name_prj
        self.send_log = send_log
        self.path_last_file_loaded = self.path_prj
        self.project_properties = load_project_properties(self.path_prj)
        self.setTitle(title)
        self.init_ui()
        # process_manager
        self.process_manager = MyProcessManager("hrr")

    def init_ui(self):
        # file_selection
        file_selection_label = QLabel(self.tr("Select a 2D mesh file :"))
        self.file_selection_listwidget = QListWidget()
        self.file_selection_listwidget.setSelectionMode(
            QAbstractItemView.ExtendedSelection)
        self.file_selection_listwidget.itemSelectionChanged.connect(
            self.names_hdf5_change)
        self.file_selection_listwidget.setVerticalScrollBarPolicy(
            Qt.ScrollBarAlwaysOff)
        self.file_selection_listwidget.verticalScrollBar().setEnabled(True)
        self.file_selection_listwidget.verticalScrollBar(
        ).valueChanged.connect(self.change_scroll_position)
        self.scrollbar = self.file_selection_listwidget.verticalScrollBar()

        file_selection_layout = QGridLayout()
        file_selection_layout.addWidget(file_selection_label, 0, 0)
        file_selection_layout.addWidget(self.file_selection_listwidget, 1, 0)
        file_selection_layout.addWidget(self.scrollbar, 1, 2)
        file_selection_layout.setColumnStretch(0, 30)
        file_selection_layout.setColumnStretch(1, 1)
        """ progress layout """
        # progress_layout
        self.progress_layout = ProcessProgLayout(
            self.compute,
            send_log=self.send_log,
            process_type="hrr",
            send_refresh_filenames=self.send_refresh_filenames)

        grid_layout = QGridLayout()
        grid_layout.addLayout(self.progress_layout, 5, 0, 1, 3)

        general_layout = QVBoxLayout()
        general_layout.addLayout(file_selection_layout)
        general_layout.addLayout(grid_layout)

        self.setLayout(general_layout)

    def update_gui(self):
        selected_file_names = [
            selection_el.text()
            for selection_el in self.file_selection_listwidget.selectedItems()
        ]
        # computing_group
        hyd_names = get_filename_by_type_physic(
            "hydraulic", os.path.join(self.path_prj, "hdf5"))
        names = hyd_names
        self.file_selection_listwidget.blockSignals(True)
        self.file_selection_listwidget.clear()
        if names:
            for name in names:
                # check
                try:
                    hdf5 = Hdf5Management(self.path_prj,
                                          name,
                                          new=False,
                                          edit=False)
                    hdf5.get_hdf5_attributes(close_file=True)
                    item_name = QListWidgetItem()
                    item_name.setText(name)
                    self.file_selection_listwidget.addItem(item_name)
                    if True:  #TODO : sort files (hdf5 attributes available for HRR) .hyd, one whole profile for all units, ...
                        pass
                    else:
                        pass
                except:
                    self.send_log.emit(
                        self.
                        tr("Error: " + name +
                           " file seems to be corrupted. Delete it with HABBY or manually."
                           ))

        self.file_selection_listwidget.blockSignals(False)
        # preselection if one
        if self.file_selection_listwidget.count() == 1:
            self.file_selection_listwidget.selectAll()

    def change_scroll_position(self, index):
        self.file_selection_listwidget.verticalScrollBar().setValue(index)

    def names_hdf5_change(self):
        selection = self.file_selection_listwidget.selectedItems()
        self.progress_layout.progress_bar.setValue(0.0)
        self.progress_layout.progress_label.setText("{0:.0f}/{1:.0f}".format(
            0.0, len(selection)))
        if selection:
            self.progress_layout.run_stop_button.setEnabled(True)
        else:
            self.progress_layout.run_stop_button.setEnabled(False)

    def compute(self):
        if len(self.file_selection_listwidget.selectedItems()) > 0:
            hrr_description = dict(
                deltatlist=[],
                hdf5_name_list=[
                    selection_el.text() for selection_el in
                    self.file_selection_listwidget.selectedItems()
                ])

            self.progress_layout.process_manager.set_hrr_hdf5_mode(
                self.path_prj, hrr_description, self.project_properties)

            # start thread
            self.progress_layout.start_process()

    def stop_compute(self):
        # stop_by_user
        self.process_manager.stop_by_user()