Example #1
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # Some buttons
        layout = QVBoxLayout()

        self.text = QPlainTextEdit()
        layout.addWidget(self.text)

        btn_run = QPushButton("Execute")
        btn_run.clicked.connect(self.start)

        layout.addWidget(btn_run)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

        # Thread runner
        self.threadpool = QThreadPool()

        self.show()

    def start(self):
        # Create a runner
        self.runner = SubProcessWorker("python dummy_script.py")
        self.runner.signals.result.connect(self.result)
        self.threadpool.start(self.runner)

    def result(self, s):
        self.text.appendPlainText(s)
Example #2
0
class QLogsWindow(QDialog):
    appendLogSignal = Signal(str)

    vbox: QVBoxLayout
    textbox: QPlainTextEdit
    clear_button: QPushButton
    _logging_handler: typing.Optional[HookableInMemoryHandler]

    def __init__(self):
        super().__init__()

        self.setWindowTitle("Logs")
        self.setMinimumSize(400, 100)
        self.resize(1000, 450)
        self.setWindowIcon(QIcon("./resources/icon.png"))

        self.vbox = QVBoxLayout()
        self.setLayout(self.vbox)

        self.textbox = QPlainTextEdit(self)
        self.textbox.setReadOnly(True)
        self.textbox.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
        self.textbox.move(10, 10)
        self.textbox.resize(1000, 450)
        self.textbox.setStyleSheet(
            "font-family: 'Courier New', monospace; background: #1D2731;")
        self.vbox.addWidget(self.textbox)

        self.clear_button = QPushButton(self)
        self.clear_button.setText("CLEAR")
        self.clear_button.setProperty("style", "btn-primary")
        self.clear_button.clicked.connect(self.clearLogs)
        self.vbox.addWidget(self.clear_button)

        self.appendLogSignal.connect(self.appendLog)

        self._logging_handler = None
        logger = logging.getLogger()
        for handler in logger.handlers:
            if isinstance(handler, HookableInMemoryHandler):
                self._logging_handler = handler
                break
        if self._logging_handler is not None:
            self.textbox.setPlainText(self._logging_handler.log)
            self.textbox.moveCursor(QTextCursor.End)
            # The Handler might be called from a different thread,
            # so use signal/slot to properly handle the event in the main thread.
            # https://github.com/dcs-liberation/dcs_liberation/issues/1493
            self._logging_handler.setHook(self.appendLogSignal.emit)
        else:
            self.textbox.setPlainText("WARNING: logging not initialized!")

    def clearLogs(self) -> None:
        if self._logging_handler is not None:
            self._logging_handler.clearLog()
        self.textbox.setPlainText("")

    def appendLog(self, msg: str):
        self.textbox.appendPlainText(msg)
        self.textbox.moveCursor(QTextCursor.End)
Example #3
0
class QTextEditLogger(logging.Handler):
    def __init__(self, parent):
        super().__init__()
        self.widget = QPlainTextEdit(parent)
        self.widget.setReadOnly(True)

    def emit(self, record):
        msg = self.format(record)
        self.widget.appendPlainText(msg)
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.urls = [
            "https://www.learnpyqt.com/",
            "https://www.mfitzp.com/",
            "https://www.google.com",
            "https://www.udemy.com/create-simple-gui-applications-with-python-and-qt/",
        ]
        # tag::init[]
        self.parsers = {  # <1>
            # Regular expression parsers, to extract data from the HTML.
            "title": re.compile(r"<title.*?>(.*?)<\/title>", re.M | re.S),
            "h1": re.compile(r"<h1.*?>(.*?)<\/h1>", re.M | re.S),
            "h2": re.compile(r"<h2.*?>(.*?)<\/h2>", re.M | re.S),
        }
        # end::init[]

        layout = QVBoxLayout()

        self.text = QPlainTextEdit()
        self.text.setReadOnly(True)

        button = QPushButton("GO GET EM!")
        button.pressed.connect(self.execute)

        layout.addWidget(self.text)
        layout.addWidget(button)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

    # tag::execute[]
    def execute(self):
        for n, url in enumerate(self.urls):
            worker = Worker(n, url, self.parsers)  # <1>
            worker.signals.data.connect(self.display_output)

            # Execute
            self.threadpool.start(worker)

    # end::execute[]

    def display_output(self, data):
        id, s = data
        self.text.appendPlainText("WORKER %d: %s" % (id, s))
Example #5
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        # Hold process reference.
        self.p = None

        layout = QVBoxLayout()

        self.text = QPlainTextEdit()
        layout.addWidget(self.text)

        self.progress = QProgressBar()
        layout.addWidget(self.progress)

        btn_run = QPushButton("Execute")
        btn_run.clicked.connect(self.start)

        layout.addWidget(btn_run)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

        self.show()

    def start(self):
        if self.p is not None:
            return

        self.p = QProcess()
        self.p.readyReadStandardOutput.connect(self.handle_stdout)
        self.p.readyReadStandardError.connect(self.handle_stderr)
        self.p.stateChanged.connect(self.handle_state)
        self.p.finished.connect(self.cleanup)
        self.p.start("python", ["dummy_script.py"])

    def handle_stderr(self):
        result = bytes(self.p.readAllStandardError()).decode("utf8")
        progress = simple_percent_parser(result)

        self.progress.setValue(progress)

    def handle_stdout(self):
        result = bytes(self.p.readAllStandardOutput()).decode("utf8")
        data = extract_vars(result)

        self.text.appendPlainText(str(data))

    def handle_state(self, state):
        self.statusBar().showMessage(STATES[state])

    def cleanup(self):
        self.p = None
Example #6
0
class Log(QWidget):
    def __init__(self, sender, title=''):
        super(Log, self).__init__()

        self.main_layout = QVBoxLayout()
        self.header_layout = QHBoxLayout()

        title_label = QLabel(title)
        title_label.setFont(QFont('Poppins', 13))
        self.header_layout.addWidget(title_label)

        holder_label = QLabel(str(sender))
        holder_label.setWordWrap(True)
        self.log_view = QPlainTextEdit()
        self.log_view.setReadOnly(True)

        self.main_layout.addLayout(self.header_layout)
        self.main_layout.addWidget(holder_label)
        self.main_layout.addWidget(self.log_view)

        self.setLayout(self.main_layout)

        self.setStyleSheet('''
            QLabel {
                border: None;
            }
            QWidget {
                color: #e9f4fb;
            }
        ''')

    def log(self, *args):
        s = ''
        for arg in args:
            s += ' ' + str(arg)
        self.log_view.appendPlainText('>  ' + s)

    def clear(self):
        self.log_view.clear()

    def removing(self):  # old method, delete later
        self.remove()

    def remove(self):
        self.log_view.setStyleSheet('background: black; color: grey;')

        remove_button = QPushButton('x')
        remove_button.clicked.connect(self.remove_clicked)

        self.header_layout.addWidget(remove_button)

    def remove_clicked(self):
        self.setParent(None)  # removes the widget
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.workers = WorkerManager()

        self.workers.status.connect(self.statusBar().showMessage)

        layout = QVBoxLayout()

        self.progress = QListView()
        self.progress.setModel(self.workers)
        delegate = ProgressBarDelegate()
        self.progress.setItemDelegate(delegate)

        layout.addWidget(self.progress)

        self.text = QPlainTextEdit()
        self.text.setReadOnly(True)

        start = QPushButton("Start a worker")
        start.pressed.connect(self.start_worker)

        clear = QPushButton("Clear")
        clear.pressed.connect(self.workers.cleanup)

        layout.addWidget(self.text)
        layout.addWidget(start)
        layout.addWidget(clear)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

    # tag::startWorker[]
    def start_worker(self):
        x = random.randint(0, 1000)
        y = random.randint(0, 1000)

        w = Worker(x, y)
        w.signals.result.connect(self.display_result)
        w.signals.error.connect(self.display_result)

        self.workers.enqueue(w)

    # end::startWorker[]

    def display_result(self, job_id, data):
        self.text.appendPlainText("WORKER %s: %s" % (job_id, data))
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.job = JobManager()

        self.job.status.connect(self.statusBar().showMessage)
        self.job.result.connect(self.display_result)

        layout = QVBoxLayout()

        self.progress = QListView()
        self.progress.setModel(self.job)
        delegate = ProgressBarDelegate()
        self.progress.setItemDelegate(delegate)

        layout.addWidget(self.progress)

        self.text = QPlainTextEdit()
        self.text.setReadOnly(True)

        button = QPushButton("Run a command")
        button.pressed.connect(self.run_command)

        clear = QPushButton("Clear")
        clear.pressed.connect(self.job.cleanup)

        layout.addWidget(self.text)
        layout.addWidget(button)
        layout.addWidget(clear)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

    # tag::startJob[]
    def run_command(self):
        self.job.execute(
            "python",
            ['dummy_script.py'],
            parsers=parsers(progress=simple_percent_parser, data=extract_vars),
        )

    # end::startJob[]

    def display_result(self, job_id, data):
        self.text.appendPlainText("WORKER %s: %s" % (job_id, data))
Example #9
0
class Log(Handler):
    def __init__(self, parent=None, width=150, height=150):
        super().__init__()
        self.widget = QPlainTextEdit(parent)
        self.widget.setPlainText("Placeholder log text\n")
        self.widget.resize(width, height)
        self.widget.setReadOnly(True)
        self.widget.setLineWrapMode(QPlainTextEdit.LineWrapMode.WidgetWidth)

    @Slot()
    @Slot(str)
    def addEntry(self, text='blo'):
        self.widget.appendPlainText(text)
        print('appending')
Example #10
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.urls = [
            "https://www.learnpyqt.com/",
            "https://www.mfitzp.com/",
            "https://www.google.com",
            "https://www.udemy.com/create-simple-gui-applications-with-python-and-qt/",
        ]

        layout = QVBoxLayout()

        self.text = QPlainTextEdit()
        self.text.setReadOnly(True)

        button = QPushButton("GO GET EM!")
        button.pressed.connect(self.execute)

        layout.addWidget(self.text)
        layout.addWidget(button)

        w = QWidget()
        w.setLayout(layout)

        self.setCentralWidget(w)

        self.show()

        self.threadpool = QThreadPool()
        print("Multithreading with maximum %d threads" %
              self.threadpool.maxThreadCount())

    def execute(self):
        for n, url in enumerate(self.urls):
            worker = Worker(n, url)
            worker.signals.data.connect(self.display_output)

            # Execute
            self.threadpool.start(worker)

    def display_output(self, data):
        id, s = data
        self.text.appendPlainText("WORKER %d: %s" % (id, s))
Example #11
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        layout = QVBoxLayout()

        self.text = QPlainTextEdit()
        layout.addWidget(self.text)

        self.progress = QProgressBar()
        self.progress.setRange(0, 100)
        self.progress.setValue(0)
        layout.addWidget(self.progress)

        btn_run = QPushButton("Execute")
        btn_run.clicked.connect(self.start)

        layout.addWidget(btn_run)

        w = QWidget()
        w.setLayout(layout)
        self.setCentralWidget(w)

        # Thread runner
        self.threadpool = QThreadPool()

        self.show()

    # tag::start[]
    def start(self):
        # Create a runner
        self.runner = SubProcessWorker(
            command="python dummy_script.py", parser=simple_percent_parser
        )
        self.runner.signals.result.connect(self.result)
        self.runner.signals.progress.connect(self.progress.setValue)
        self.threadpool.start(self.runner)

    # end::start[]

    def result(self, s):
        self.text.appendPlainText(s)
Example #12
0
class LoggerTextboxWidget(logging.Handler, QWidget):
    """The LoggerTextboxWidget class provides a textbox widget that can also work as a
    logging handler for the Python logging system.

    Examples:
        textbox_logger = LoggerTextboxWidget()
        logging.getLogger().addHandler(textbox_logger)
    """
    def __init__(self, formatter: "logging.Formatter", parent: QWidget = None):
        logging.Handler.__init__(self)
        QWidget.__init__(self, parent)

        self.setFormatter(formatter)

        self._textbox = QPlainTextEdit(self)
        self._textbox.setReadOnly(True)

        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self._textbox)
        self.setLayout(layout)

    @property
    def text(self) -> str:
        """Returns the text written on the textbox."""
        return self._textbox.toPlainText()

    def set_plain_text(self, text: str):
        """Replaces the textbox content with `text`."""
        self._textbox.setPlainText(text)

    def emit(self, record):
        """This method is called each time a logger emits a message. It applies the
        corresponding format and sends it to the textbox."""
        msg = self.format(record)
        self._textbox.appendPlainText(msg)
Example #13
0
class UserTab(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        layout = QVBoxLayout(self)
        self.text = QPlainTextEdit()
        layout.addWidget(self.text)
        self.setLayout(layout)
        self.ds = DataSource()
        self.worker = UpdateUserWorker()
        self.worker_thread = QThread()
        self.worker_thread.started.connect(self.worker.run)
        self.worker.finished.connect(self.worker_thread.quit)
        self.worker.moveToThread(self.worker_thread)
        self.worker_thread.start()
        self.worker.processed.connect(self.processed)

    @Slot(dict)
    def processed(self, user):
        self.text.appendPlainText('USER: {}'.format(str(user)))

    def finish(self):
        self.worker.finish()
        self.worker_thread.quit()
        self.worker_thread.wait()
Example #14
0
class RunTab(QtWidgets.QWidget):

    run_checks = QtCore.Signal()

    def __init__(self, prj: QAXProject):
        super(RunTab, self).__init__()
        self.prj = prj
        self.check_executor = None

        self.vbox = QtWidgets.QVBoxLayout()
        self.setLayout(self.vbox)

        self._add_check_outputs()
        self._add_process()

        # final setup
        self.set_run_stop_buttons_enabled(False)

    def _add_check_outputs(self):
        co_groupbox = QGroupBox("Check outputs")
        co_groupbox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        co_layout = QVBoxLayout()
        co_layout.setSpacing(16)
        co_groupbox.setLayout(co_layout)

        self.qajson_spatial_checkbox = QCheckBox(
            "Include summary spatial output in QAJSON. "
            "Supports QAX visualisation.")
        self.qajson_spatial_checkbox.setCheckState(
            QtCore.Qt.CheckState.Checked)
        co_layout.addWidget(self.qajson_spatial_checkbox)

        export_layout = QVBoxLayout()
        export_layout.setSpacing(4)
        self.export_spatial_checkbox = QCheckBox(
            "Export detailed spatial outputs to file. "
            "Supports visualisation in other geospatial applications.")
        self.export_spatial_checkbox.stateChanged.connect(
            self._on_export_spatial_changed)
        export_layout.addWidget(self.export_spatial_checkbox)

        output_folder_layout = QHBoxLayout()
        output_folder_layout.setSpacing(4)
        output_folder_layout.addSpacerItem(QtWidgets.QSpacerItem(37, 20))
        self.output_folder_label = QLabel(
            "Detailed spatial output folder location:")
        output_folder_layout.addWidget(self.output_folder_label)
        self.output_folder_input = QLineEdit()
        self.output_folder_input.setText(
            GuiSettings.settings().value("spatial_outputs"))
        self.output_folder_input.setMinimumWidth(300)
        self.output_folder_input.setSizePolicy(QSizePolicy.Expanding,
                                               QSizePolicy.Expanding)
        output_folder_layout.addWidget(self.output_folder_input)

        self.open_output_folder_button = QPushButton()
        output_folder_layout.addWidget(self.open_output_folder_button)
        self.open_output_folder_button.setIcon(qta.icon('fa.folder-open'))
        self.open_output_folder_button.setToolTip(
            f"Select file containing data")
        self.open_output_folder_button.clicked.connect(
            self._click_open_spatial_export_folder)
        export_layout.addLayout(output_folder_layout)

        co_layout.addLayout(export_layout)

        self._on_export_spatial_changed()
        self.vbox.addWidget(co_groupbox)

    def _click_open_spatial_export_folder(self):
        output_folder = QFileDialog.getExistingDirectory(
            self, f"Select folder for spatial outputs",
            GuiSettings.settings().value("spatial_outputs"),
            QFileDialog.ShowDirsOnly)

        if os.path.exists(output_folder):
            GuiSettings.settings().setValue("spatial_outputs", output_folder)

        self.output_folder_input.setText(output_folder)

    def _on_export_spatial_changed(self):
        is_export = self.export_spatial_checkbox.isChecked()
        self.output_folder_label.setEnabled(is_export)
        self.output_folder_input.setEnabled(is_export)
        self.open_output_folder_button.setEnabled(is_export)

    def _add_process(self):
        process_groupbox = QGroupBox("Process")
        process_groupbox.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Expanding)
        process_layout = QVBoxLayout()
        process_layout.setSpacing(0)
        process_groupbox.setLayout(process_layout)

        pbar_frame = QFrame()
        pbar_frame.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        pbar_hbox = QHBoxLayout()
        pbar_hbox.setContentsMargins(QtCore.QMargins(0, 0, 0, 16))
        pbar_hbox.setSpacing(16)

        # Run and stop buttons
        hbox = QHBoxLayout()
        hbox.setSpacing(8)
        self.run_button = QPushButton()
        # is only enabled when validation passes
        self.run_button.setEnabled(False)
        self.run_button.setText("Run")
        self.run_button.setToolTip("Start check execution")
        self.run_button.setFixedWidth(100)
        run_icon = qta.icon('fa.play', color='green')
        self.run_button.setIcon(run_icon)
        self.run_button.clicked.connect(self._click_run)
        hbox.addWidget(self.run_button)

        self.stop_button = QPushButton()
        self.stop_button.setEnabled(False)
        self.stop_button.setText("Stop")
        self.stop_button.setToolTip("Stop check execution")
        self.stop_button.setFixedWidth(100)
        stop_icon = qta.icon('fa.stop', color='red')
        self.stop_button.setIcon(stop_icon)
        self.stop_button.clicked.connect(self._click_stop)
        hbox.addWidget(self.stop_button)

        self.progress_bar = QProgressBar()
        self.progress_bar.setTextVisible(True)
        self.progress_bar.setAlignment(QtCore.Qt.AlignCenter)
        self.progress_bar.setValue(0)
        self.progress_bar.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)

        pbar_hbox.addLayout(hbox)
        pbar_hbox.addWidget(self.progress_bar)
        pbar_frame.setLayout(pbar_hbox)
        process_layout.addWidget(pbar_frame)

        vbox = QVBoxLayout()
        vbox.setSpacing(8)
        vbox.setContentsMargins(QtCore.QMargins(0, 0, 0, 16))
        process_layout.addLayout(vbox)
        hbox = QHBoxLayout()
        vbox.addLayout(hbox)
        check_name_label = QLabel("Check:")
        check_name_label.setFixedWidth(80)
        hbox.addWidget(check_name_label)
        self.check_name_text_label = QLabel("n/a")
        hbox.addWidget(self.check_name_text_label)

        hbox = QHBoxLayout()
        vbox.addLayout(hbox)
        status_name_label = QLabel("Status:")
        status_name_label.setFixedWidth(80)
        hbox.addWidget(status_name_label)
        self.status_name_text_label = QLabel("Not started")
        hbox.addWidget(self.status_name_text_label)

        self.warning_frame = QFrame()
        self.warning_frame.setVisible(False)
        self.warning_frame.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Fixed)
        hbox = QHBoxLayout()

        warning_icon_widget = qta.IconWidget('fa.warning', color='red')
        warning_icon_widget.setIconSize(QtCore.QSize(48, 48))
        warning_icon_widget.update()
        hbox.addWidget(warning_icon_widget)
        warning_label = QLabel(
            "Grid Transformer did not complete successfully. Please refer to "
            "log output.")
        warning_label.setStyleSheet("QLabel { color: red; }")
        warning_label.setWordWrap(True)
        warning_label.setSizePolicy(QSizePolicy.Expanding,
                                    QSizePolicy.Preferred)
        hbox.addWidget(warning_label)
        self.warning_frame.setLayout(hbox)
        process_layout.addWidget(self.warning_frame)

        self.success_frame = QFrame()
        self.success_frame.setVisible(False)
        self.success_frame.setSizePolicy(QSizePolicy.Expanding,
                                         QSizePolicy.Fixed)
        hbox = QHBoxLayout()

        success_icon_widget = qta.IconWidget('fa.check', color='green')
        success_icon_widget.setIconSize(QtCore.QSize(48, 48))
        success_icon_widget.update()
        hbox.addWidget(success_icon_widget)
        success_label = QLabel("All checks completed successfully.")
        success_label.setStyleSheet("QLabel { color: green; }")
        success_label.setWordWrap(True)
        success_label.setSizePolicy(QSizePolicy.Expanding,
                                    QSizePolicy.Preferred)
        hbox.addWidget(success_label)
        self.success_frame.setLayout(hbox)
        process_layout.addWidget(self.success_frame)

        log_layout = QVBoxLayout()
        log_layout.setSpacing(4)
        log_label = QLabel("Log messages")
        log_label.setStyleSheet("QLabel { color: grey; }")
        log_layout.addWidget(log_label)

        self.log_messages = QPlainTextEdit()
        log_font = QFont("monospace")
        log_font.setStyleHint(QFont.TypeWriter)
        self.log_messages.setFont(log_font)
        self.log_messages.setReadOnly(True)
        self.log_messages.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        log_layout.addWidget(self.log_messages)
        process_layout.addLayout(log_layout)

        self.vbox.addWidget(process_groupbox)

    def set_run_stop_buttons_enabled(self, is_running: bool) -> NoReturn:
        if is_running:
            self.run_button.setEnabled(False)
            self.stop_button.setEnabled(True)
        else:
            self.run_button.setEnabled(True)
            self.stop_button.setEnabled(False)

    def _log_message(self, message):
        self.log_messages.appendPlainText(message)

    def run_executor(self, check_executor: QtCheckExecutorThread):
        # we pass the check_executor into the run tab as this is where the UI
        # components are that will display the execution status.
        self.set_run_stop_buttons_enabled(True)

        self._log_message("Check execution started")
        self.start_time = time.perf_counter()

        self.check_executor = check_executor
        self.check_executor.options = self.get_options()
        self.check_executor.check_tool_started.connect(
            self._on_check_tool_started)
        self.check_executor.progress.connect(self._on_progress)
        self.check_executor.qajson_updated.connect(self._on_qajson_update)
        self.check_executor.checks_complete.connect(self._on_checks_complete)
        self.check_executor.status_changed.connect(self._on_status_change)
        self.check_executor.start()

    def get_options(self) -> Dict:
        ''' Gets a list of options based on user entered data. eg; the spatial
        output specifications.
        '''
        return {
            CheckOption.spatial_output_qajson:
            self.qajson_spatial_checkbox.isChecked(),
            CheckOption.spatial_output_export:
            self.export_spatial_checkbox.isChecked(),
            CheckOption.spatial_output_export_location:
            self.output_folder_input.text()
        }

    def _click_run(self):
        self.run_checks.emit()

    def _click_stop(self):
        if self.check_executor is None:
            logger.warn("Check executor does not exist, cannot stop")
            return
        self._log_message("Stopping check execution")
        self.check_executor.stop()

    @QtCore.Slot(float)
    def _on_progress(self, progress):
        self.progress_bar.setValue(int(progress * 100))

    @QtCore.Slot()
    def _on_qajson_update(self):
        self.prj.qa_json = self.check_executor.qa_json

    @QtCore.Slot(object)
    def _on_check_tool_started(self, tpl):
        check_tool_name, check_number, total_check_count = tpl
        self.check_name_text_label.setText("{} ({}/{})".format(
            check_tool_name, check_number, total_check_count))

    @QtCore.Slot()
    def _on_checks_complete(self):
        run_time = time.perf_counter() - self.start_time
        self._log_message(
            f"Execution time for all checks = {run_time:.2f} sec")
        self._log_message("\n\n")

        self.set_run_stop_buttons_enabled(False)
        self.prj.qa_json = self.check_executor.qa_json

    @QtCore.Slot(str)
    def _on_status_change(self, status):
        self.status_name_text_label.setText(status)
Example #15
0
File: Log.py Project: zsh2020/Ryven
class Log(QWidget):
    def __init__(self, sender, title=''):
        super(Log, self).__init__()

        self.main_layout = QVBoxLayout()
        self.header_layout = QHBoxLayout()

        title_label = QLabel(title)
        title_label.setFont(QFont('Poppins', 13))
        self.header_layout.addWidget(title_label)

        self.remove_button = QPushButton('x')
        self.remove_button.clicked.connect(self.remove_clicked)
        self.header_layout.addWidget(self.remove_button)
        self.remove_button.hide()

        holder_label = QLabel(shorten(str(sender), 76))
        holder_label.setWordWrap(True)
        self.log_view = QPlainTextEdit()
        self.log_view.setReadOnly(True)

        self.main_layout.addLayout(self.header_layout)
        self.main_layout.addWidget(holder_label)
        self.main_layout.addWidget(self.log_view)

        self.setLayout(self.main_layout)

        self.enabled_style_sheet = '''
            QLabel {
                border: None;
            }
            QWidget {
                color: #e9f4fb;
            }
        '''
        self.disabled_style_sheet = '''
            QLabel {
                border: None;
            }
            QWidget {
                color: #e9f4fb;
            }
            QPlainTextEdit {
                background: black; 
                color: grey;
            }
        '''
        self.setStyleSheet(self.enabled_style_sheet)

    def log(self, *args):
        s = ''
        for arg in args:
            s += ' ' + str(arg)
        self.log_view.appendPlainText('>  ' + s)

    def clear(self):
        self.log_view.clear()

    def disable(self):
        self.remove_button.show()
        self.setStyleSheet(self.disabled_style_sheet)

    def enable(self):
        self.remove_button.hide()
        self.setStyleSheet(self.enabled_style_sheet)
        self.show()

    def remove_clicked(self):
        self.hide()
class TrainingConsoleWidget(QWidget):
    """The TrainingConsoleWidget provides a widget for controlling the training status
    of a model, in a simple way. (Analog of the console output in Keras, but with a few
    more options).

    It also can save and show an history of the last trained models.
    """

    training_started = Signal()
    training_stopped = Signal()

    class TrainingStatus(Enum):
        Running = 1
        Stopped = 2
        Not_Compiled = 3

    def __init__(self, parent: "QWidget" = None):
        super().__init__(parent)

        # Components
        self._pretrained_model: Optional["keras.models.Model"] = None
        self._ttv: Optional["TTVSets"] = None
        self._hyperparameters: Optional[Dict] = None
        self._callbacks: List[Callback] = []

        self._trained_model: Optional["keras.models.Model"] = None

        # Widgets
        self._start_training_button = QPushButton("Start training")
        self._stop_training_button = QPushButton("Stop training")

        self._buttons_layout = QHBoxLayout()
        self._buttons_layout.addWidget(self._start_training_button)
        self._buttons_layout.addWidget(self._stop_training_button)

        self._status_label = QLabel()

        self._batch_progress_bar = QProgressBar()
        self._epoch_progress_bar = QProgressBar()

        self.training_output_textbox = QPlainTextEdit()
        self.training_output_textbox.setReadOnly(True)

        console_output_group = QGroupBox("Console output")
        console_output_layout = QVBoxLayout()
        console_output_layout.setContentsMargins(0, 0, 0, 0)
        console_output_layout.addWidget(self.training_output_textbox)
        console_output_group.setLayout(console_output_layout)

        self._main_layout = QVBoxLayout()
        self._main_layout.addLayout(self._buttons_layout)
        self._main_layout.addWidget(self._status_label, Qt.AlignRight)
        self._main_layout.addWidget(console_output_group)
        self._main_layout.addWidget(self._batch_progress_bar)
        self._main_layout.addWidget(self._epoch_progress_bar)
        self.setLayout(self._main_layout)

        # Connections
        self._start_training_button.clicked.connect(self.start_training)
        self._stop_training_button.clicked.connect(self.stop_training)

        # Inner workings
        self.training_status = self.TrainingStatus.Not_Compiled
        self._training_thread = None

    @property
    def training_status(self):
        """Returns the current status of the training (Running, Stopped...)"""
        return self._training_status

    @training_status.setter
    def training_status(self, new_status):
        """Changes the training status.

        Doing so will update the interface accordingly.
        """
        self._training_status = new_status

        if self._training_status == self.TrainingStatus.Running:
            self._start_training_button.setEnabled(False)
            self._stop_training_button.setEnabled(True)
            self._status_label.setText("Running")
            self.start_training

        elif self._training_status == self.TrainingStatus.Stopped:
            self._start_training_button.setEnabled(True)
            self._stop_training_button.setEnabled(False)
            self._status_label.setText("Stopped")

        elif self._training_status == self.TrainingStatus.Not_Compiled:
            self._start_training_button.setEnabled(True)
            self._stop_training_button.setEnabled(False)
            self._status_label.setText("Not Compiled")

    def set_ttv(self, ttv: "TTVSets"):
        """Sets the Train/Test/Validation models used for training."""
        self._ttv = ttv

    def set_pretrained_model(self, pretrained_model: "Model"):
        """Sets a new pretrained model for training."""
        self._pretrained_model = pretrained_model

        self.training_status = self.TrainingStatus.Not_Compiled

    def set_hyperparameters(self, hyperparameters: Dict):
        """Sets new hyperparameters for training."""
        self._hyperparameters = hyperparameters

        self.training_status = self.TrainingStatus.Not_Compiled

    def set_callbacks(self, callbacks: List[Callback]):
        self._callbacks = callbacks

    def get_trained_model(self):
        """Returns the model after it has been trained."""
        return self._trained_model

    def compile_model(self):
        """Compile the model with the passed hyperparameters. The dataset is needed for
        the input shape."""
        LOGGER.info("Starting to compile the model...")

        if not self._is_input_ready():
            return False

        # Create a new model based on the pretrained one, but with a new InputLayer
        # compatible with the dataset
        if self._pretrained_model.layers[0].__class__.__name__ != "InputLayer":
            input_layer = Input(self._ttv.train.input_shape)

            output = self._pretrained_model(input_layer)
            self._trained_model = Model(input_layer, output)
        else:
            self._trained_model = self._pretrained_model

        try:
            self._trained_model.compile(
                optimizer=self._hyperparameters["optimizer"],
                loss=self._hyperparameters["loss_function"],
                metrics=["accuracy"],
            )

            self._trained_model.summary()

            LOGGER.info("Model compiled successfully!!")

            self.training_status = self.TrainingStatus.Stopped

            return True

        except Exception as err:
            LOGGER.exception("Model Compiling error: ", err)

            self.training_output_textbox.setPlainText(
                "> Error while compiling the model:\n", str(err))

        return False

    def start_training(self):
        """Starts the training on a new thread."""
        if self.training_status == self.TrainingStatus.Not_Compiled:
            successfully_compiled = self.compile_model()

            if not successfully_compiled:
                LOGGER.info("Couldn't compile model. Training not started.")
                return

        total_train_batches = len(self._ttv.train)
        total_train_epochs = self._hyperparameters["epochs"]

        self._batch_progress_bar.setMaximum(total_train_batches)
        self._epoch_progress_bar.setMaximum(total_train_epochs)
        self._epoch_progress_bar.setValue(0)
        self.training_output_textbox.clear()

        def epoch_begin_update(epoch: int, logs):
            message = f"==== Epoch {epoch + 1}/{total_train_epochs} ===="

            LOGGER.info(message)
            self.training_output_textbox.appendPlainText(message)
            self._epoch_progress_bar.setValue(epoch)

        def batch_end_update(batch: int, logs):
            # Update progress
            self._batch_progress_bar.setValue(batch)

            # Log metrics on console
            message = f"{batch}/{total_train_batches}"

            for (k, v) in list(logs.items()):
                message += f" - {k}: {v:.4f}"

            LOGGER.info(message)
            self.training_output_textbox.appendPlainText(message)

        def train_end_update(logs):
            # Put the progress bar at 100% when the training ends
            self._batch_progress_bar.setValue(
                self._batch_progress_bar.maximum())
            self._epoch_progress_bar.setValue(
                self._epoch_progress_bar.maximum())

            # Stop the training
            self.stop_training()

        # Connect callbacks
        signals_callback = SignalsCallback()
        signals_callback.epoch_begin.connect(epoch_begin_update)
        signals_callback.train_batch_end.connect(batch_end_update)
        signals_callback.train_end.connect(train_end_update)

        self.training_stopped.connect(signals_callback.stop_model)

        print(self._callbacks)
        # log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y_%m_%d-%H_%M_%S")

        # tb = program.TensorBoard()
        # tb.configure(argv=[None, "--logdir", log_dir])
        # url = tb.launch()
        # print("Launched Tensorboard instance in:", url)

        # tf_callback=tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
        # tf_callback.set_model(self._trained_model)

        # Start training
        self._fit_worker = FitWorker(
            self._trained_model,
            self._ttv.train,
            self._hyperparameters,
            callbacks=[signals_callback] + self._callbacks,
        )

        self.training_status = self.TrainingStatus.Running
        self._fit_worker.start()

        self.training_started.emit()

    def stop_training(self):
        """Stops the training."""
        self.training_status = self.TrainingStatus.Stopped

        self.training_stopped.emit()

    def _is_input_ready(self) -> bool:
        """Checks if the input values used for training (model, dataset,
        hyperparameters...) are valid."""
        message = ""

        if not self._ttv.train:
            message += "> Training dataset not specified\n"

        if not self._pretrained_model:
            message += "> Model not specified.\n"

        if not self._hyperparameters:
            message += "> Hyperparameters not specified.\n"

        if message:
            self.training_output_textbox.setPlainText(message)
            LOGGER.info(message)
            return False

        return True

    def sizeHint(self) -> "QSize":
        """Returns the expected size of the widget."""
        return QSize(500, 300)

    def __reduce__(self):
        return (TrainingConsoleWidget, ())
Example #17
0
class application(QTabWidget):
    bot = 0

    def __init__(self, parent=None):
        super(application, self).__init__(parent)
        self.bot = None
        self.db = sqlite3.connect('database')
        # tabs
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tab3 = QWidget()
        self.tab4 = QWidget()
        self.tab5 = QWidget()
        self.resize(640, 400)

        self.addTab(self.tab1, "Tab 1")
        self.addTab(self.tab2, "Tab 2")
        self.addTab(self.tab3, "Tab 3")
        self.addTab(self.tab4, "Tab 4")
        self.addTab(self.tab5, "Tab 5")

        # tab set keys
        self.h_box_key = QHBoxLayout()
        self.change_key_b = QPushButton("Edit keys")
        self.edit_1 = QLineEdit()
        self.edit_2 = QLineEdit()
        self.edit_3 = QLineEdit()
        self.edit_4 = QLineEdit()
        self.result = QLabel()
        self.set_button = QPushButton("Set keys")
        self.handle_info = QLabel()
        self.follower_info = QLabel()
        self.ready_lab = QLabel()

        # tab follow
        self.box_label = QLabel("Link to tweet")
        self.combo_label = QLabel("Mode")
        self.spin_label = QLabel("Limit before sleep")
        self.prog_bar = QProgressBar()
        self.combo_box = QComboBox()
        self.h_box = QHBoxLayout()
        self.spin_box = QSpinBox()
        self.link_box = QLineEdit()
        self.link_result = QLabel()
        self.follow_button = QPushButton("Follow Retweeters")
        self.cancel_button = QPushButton("Cancel")
        self.logger = QPlainTextEdit()
        self.h_box2 = QHBoxLayout()
        self.max_box = QSpinBox()
        self.max_label = QLabel("Max follows before stop")

        # tab unfollow
        self.unfollow_button = QPushButton("Unfollow Auto followers")
        self.unf_logger = QPlainTextEdit()
        self.unfollow_res = QLabel()
        self.prog_bar_unf = QProgressBar()
        self.unfollow_cancel = QPushButton("Cancel")
        self.unf_confirm = QMessageBox()

        # tab help
        self.help_box = QPlainTextEdit()
        self.help_label = QLabel(
            "<a href='http://Optumsense.com/'>http://Optumsense.com/</a>")

        #tab schedule
        self.tweet_box = QPlainTextEdit()
        self.date_time = QDateTimeEdit(QDateTime.currentDateTime())
        self.schedule_but = QPushButton("Schedule Tweet")
        self.schedule_info = QLabel()
        self.schedule_table = QTableView()

        # threads
        self.follow_thread = None
        self.unfollow_thread = None
        self.schedule_thread = None

        # tabs
        self.tab1UI()
        self.tab2UI()
        self.tab3UI()
        self.tab4UI()
        self.tab5UI()

        self.setWindowTitle("Optumize")
        self.setWindowIcon(QtGui.QIcon('assets/oo.png'))

        # db
        cursor = self.db.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS keys(one TEXT, two TEXT, three TEXT, four TEXT)'''
                       )
        self.db.commit()

    def tab1UI(self):
        layout = QFormLayout()
        layout.addRow(self.h_box)
        self.h_box.addWidget(self.combo_label)
        self.combo_label.setAlignment(Qt.AlignRight)
        self.h_box.addWidget(self.combo_box)
        self.combo_box.addItem("Follow Retweeters")
        self.combo_box.addItem("Follow Followers")
        self.combo_box.currentIndexChanged.connect(self.selection_change)

        self.h_box.addWidget(self.spin_label)
        self.spin_label.setAlignment(Qt.AlignRight)
        self.h_box.addWidget(self.spin_box)
        self.spin_box.setMinimum(1)
        self.spin_box.setValue(30)

        layout.addRow(self.box_label, self.link_box)
        self.link_result.setAlignment(Qt.AlignCenter)
        layout.addRow(self.link_result)
        layout.addRow(self.follow_button)
        self.follow_button.clicked.connect(self.follow_ret)

        layout.addRow(self.cancel_button)
        self.cancel_button.clicked.connect(self.cancel_onclick)
        layout.addRow(self.h_box2)
        self.h_box2.addWidget(self.max_label)
        self.h_box2.addWidget(self.max_box)
        self.max_box.setFixedWidth(100)
        self.max_label.setAlignment(Qt.AlignRight)
        self.max_box.setMaximum(1000000)
        self.max_box.setValue(100)
        self.max_label.hide()
        self.max_box.hide()
        layout.addRow(self.logger)

        self.logger.setReadOnly(True)
        layout.addRow(self.prog_bar)
        self.prog_bar.setAlignment(Qt.AlignCenter)
        self.setTabText(0, "Follow")
        self.setTabIcon(0, QtGui.QIcon('assets/check_mark.png'))
        self.tab1.setLayout(layout)

    def selection_change(self, i):
        if i == 0:
            self.box_label.setText("Link to tweet")
            self.follow_button.setText("Follow Retweeters")
            self.link_result.setText("")
            self.max_label.hide()
            self.max_box.hide()
            self.follow_button.clicked.connect(self.follow_ret)
        else:
            self.box_label.setText("Handle of user")
            self.follow_button.setText("Follow Followers")
            self.link_result.setText("")
            self.max_label.show()
            self.max_box.show()
            self.max_label.setText("Max follows before stop")
            self.follow_button.clicked.connect(self.follow_fol)

    def cancel_onclick(self):
        if self.follow_thread is None:
            pass
        elif self.follow_thread.isRunning():
            self.prog_bar.setValue(0)
            self.logger.appendPlainText("Cancelled script")
            self.follow_thread.terminate()
            self.follow_thread = None

    def follow_ret(self):
        self.prog_bar.setValue(0)
        self.follow_button.setEnabled(False)
        self.link_result.setText("")
        self.logger.clear()
        limit = self.spin_box.value()
        if self.bot is None:
            self.link_result.setText(
                "<font color='red'>Configure access keys in set keys tab</font>"
            )
            return
        if self.follow_thread is not None:
            return
        link = self.link_box.text()
        id_tweet = link.split("/")[-1]
        try:
            tweet = self.bot.api.get_status(id_tweet)

            self.logger.appendPlainText(
                f"following retweeters from link: {link}...")
            self.follow_thread = FollowThread(self.bot, id_tweet, limit, 1, 0)
            self.follow_thread.start()
            self.connect(self.follow_thread, SIGNAL("finished()"), self.done)
            self.connect(self.follow_thread, SIGNAL("setup_prog(QString)"),
                         self.setup_prog)
            self.connect(self.follow_thread, SIGNAL("post_follow(QString)"),
                         self.post_follow)
        except tweepy.error.TweepError:
            self.follow_button.setEnabled(True)
            self.link_result.setText(
                "<font color='red'>Could not find tweet</font>")

    def setup_prog(self, msg):
        self.prog_bar.setMaximum(int(msg))

    def follow_fol(self):
        self.prog_bar.setValue(0)
        self.follow_button.setEnabled(False)
        self.link_result.setText("")
        self.logger.clear()
        limit = self.spin_box.value()
        if self.bot is None:
            self.link_result.setText(
                "<font color='red'>Configure access keys in set keys tab</font>"
            )
            return
        if self.follow_thread is not None:
            return
        handle = self.link_box.text()
        if handle == '':
            self.link_result.setText(
                "<font color='red'>Enter a handle above</font>")
            return
        elif handle[0] == '@':
            id_user = handle[1:]
        else:
            id_user = handle
        try:
            man = self.bot.api.get_user(id_user)
            self.logger.appendPlainText(
                f"following followers of {man.screen_name}...")
            self.logger.appendPlainText(f"Collecting")
            self.follow_thread = FollowThread(self.bot, id_user, limit, 2,
                                              self.max_box.value())
            self.follow_thread.start()
            self.connect(self.follow_thread, SIGNAL("finished()"), self.done)
            self.connect(self.follow_thread, SIGNAL("setup_prog(QString)"),
                         self.setup_prog)
            self.connect(self.follow_thread, SIGNAL("post_follow(QString)"),
                         self.post_follow)
        except tweepy.error.TweepError:
            self.follow_button.setEnabled(True)
            self.link_result.setText(
                "<font color='red'>Could not find user</font>")

    def post_follow(self, message):
        if message == "bad":
            self.logger.appendPlainText(
                "Rate limit exceeded... sleeping for cooldown")
        else:
            self.logger.appendPlainText(message)
            self.prog_bar.setValue(self.prog_bar.value() + 1)

    def done(self):
        self.follow_thread = None
        self.follow_button.setEnabled(True)

    def tab2UI(self):
        layout = QFormLayout()
        layout.addRow(self.unfollow_button)
        layout.addRow(self.unfollow_cancel)
        layout.addRow(self.unfollow_res)
        self.unfollow_res.setAlignment(Qt.AlignCenter)
        self.unfollow_button.clicked.connect(self.unfollow_fol)
        self.unfollow_cancel.clicked.connect(self.unfollow_can)
        layout.addWidget(self.unf_logger)
        self.unf_logger.setReadOnly(True)
        layout.addRow(self.prog_bar_unf)
        self.prog_bar_unf.setAlignment(Qt.AlignCenter)
        self.setTabText(1, "Unfollow")
        self.setTabIcon(1, QtGui.QIcon('assets/cross.png'))
        self.tab2.setLayout(layout)

    def unfollow_fol(self):
        self.unfollow_button.setEnabled(False)
        self.unfollow_thread = UnfollowThread(self.bot)
        self.unfollow_thread.start()
        self.connect(self.unfollow_thread, SIGNAL("post_unfol(QString)"),
                     self.post_unfol)
        self.connect(self.unfollow_thread, SIGNAL("finished()"), self.done_unf)

    def done_unf(self):
        self.unfollow_thread = None
        self.unf_logger.appendPlainText("Done")
        self.unfollow_button.setEnabled(True)

    def post_unfol(self, msg):
        if msg == "bad":
            self.unf_logger.appendPlainText(
                "rate limit exceeded, resting for 15 minutes")
        else:
            self.unf_logger.appendPlainText(f"Unfollowing {msg}")

    def unfollow_can(self):
        if self.unfollow_thread is None:
            pass
        elif self.unfollow_thread.isRunning():
            self.unf_logger.appendPlainText("Cancelled script")
            self.unfollow_thread.terminate()
            self.unfollow_thread = None

    def tab3UI(self):
        layout = QFormLayout()
        layout.addWidget(self.tweet_box)
        self.tweet_box.setMaximumHeight(150)
        self.tweet_box.setPlaceholderText("Tweet contents")
        layout.addRow(self.date_time)
        self.date_time.setCalendarPopup(True)
        layout.addRow(self.schedule_info)
        layout.addRow(self.schedule_but)
        self.schedule_but.clicked.connect(self.schedule_tweet)
        layout.addWidget(self.schedule_table)
        self.setTabText(2, "Schedule Tweet")
        self.setTabIcon(2, QtGui.QIcon('assets/calendar.png'))
        self.tab3.setLayout(layout)

    def schedule_tweet(self):
        tweet_contents = self.tweet_box.toPlainText()
        if (len(tweet_contents) == 0):
            print("length of tweet is 0")
            self.schedule_info.setText("length of tweet is 0")
            return
        elif (len(tweet_contents) >= 280):
            self.schedule_info.setText("Tweet char limit exceeded")
            return
        if self.bot is None:
            self.schedule_info.setText(
                "<font color='red'>Configure access keys in set keys tab</font>"
            )
            return
        datetime = self.date_time.text()
        try:
            print("done")
            self.schedule_thread.start()
            self.schedule_thread.add_tweet(tweet_contents, datetime)
        except:
            self.follow_button.setEnabled(True)
            self.link_result.setText(
                "<font color='red'>Could not find user</font>")

    def done_schedule(self):
        print("done scheduler")

    def tab4UI(self):
        layout = QFormLayout()
        layout.addRow("API key", self.edit_1)
        layout.addRow("API key secret", self.edit_2)
        layout.addRow("Auth token", self.edit_3)
        layout.addRow("Auth token secret", self.edit_4)
        self.set_button.clicked.connect(self.set_keys)
        l = self.read_file()
        if l is not None:
            if len(l) == 4:
                self.edit_1.setText(l[0])
                self.edit_2.setText(l[1])
                self.edit_3.setText(l[2])
                self.edit_4.setText(l[3])
                self.set_keys()
        layout.addRow(self.result)
        self.result.setAlignment(Qt.AlignCenter)
        layout.addRow(self.h_box_key)
        self.h_box_key.addWidget(self.change_key_b)
        self.h_box_key.addWidget(self.set_button)
        self.change_key_b.clicked.connect(self.change_keys)
        layout.addRow(self.handle_info)
        self.handle_info.setAlignment(Qt.AlignCenter)
        layout.addRow(self.follower_info)
        self.follower_info.setAlignment(Qt.AlignCenter)
        layout.addRow(self.ready_lab)
        self.ready_lab.setAlignment(Qt.AlignCenter)
        self.setTabText(3, "Settings")
        self.setTabIcon(3, QtGui.QIcon('assets/settings.png'))
        self.tab4.setLayout(layout)

    def change_keys(self):
        self.set_button.setEnabled(True)

    def set_keys(self):
        self.set_button.setEnabled(False)
        self.result.setText("")
        one = self.edit_1.text()
        two = self.edit_2.text()
        three = self.edit_3.text()
        four = self.edit_4.text()
        try:
            self.bot = apiconnector.ApiConnector(one, two, three, four)
            me = self.bot.add_keys(one, two, three, four)
            self.handle_info.setText("Handle: @" + me.screen_name)
            self.follower_info.setText("Followers: " + str(me.followers_count))
            self.ready_lab.setText("<font color='green'>Ready!</font>")
            cursor = self.db.cursor()
            cursor.execute('DELETE FROM keys;', )
            cursor.execute(
                '''INSERT INTO keys(one, two, three, four)
                  VALUES(?,?,?,?)''', (one, two, three, four))
            self.db.commit()
            self.schedule_thread = ScheduleThread(self.bot)
        except:
            print("Could not authenticate you")
            self.result.setText(
                "<font color='red'>Could not authenticate you</font>")

    def read_file(self):
        result = []
        try:
            cursor = self.db.cursor()
            cursor.execute('''SELECT one, two, three, four FROM keys''')
            all_rows = cursor.fetchall()
            for row in all_rows:
                result.append(row[0])
                result.append(row[1])
                result.append(row[2])
                result.append(row[3])
            return result

        except:
            return None

    def tab5UI(self):
        layout = QFormLayout()
        layout.addRow("Website", self.help_label)
        self.help_label.setOpenExternalLinks(True)
        self.setTabText(4, "Help")
        self.setTabIcon(4, QtGui.QIcon('assets/help.png'))
        self.tab5.setLayout(layout)
Example #18
0
class PDLEditor(QWidget):
    def __init__(self):
        QWidget.__init__(self)
        self.setLayout(QGridLayout())

        split = QSplitter(Qt.Horizontal)
        split.setChildrenCollapsible(False)

        self.vis_area = WidgetVisualizationArea()
        split.addWidget(self.vis_area)

        edit_pane = QWidget()
        edit_pane.setLayout(QVBoxLayout())

        font = QFont('Courier New', 11)

        self.editor = QPlainTextEdit()
        self.editor.document().setDefaultFont(font)
        edit_pane.layout().addWidget(self.editor)

        compile_b = QPushButton("Compile")
        compile_b.clicked.connect(self.compilePDL)
        edit_pane.layout().addWidget(compile_b)

        self.messages = QPlainTextEdit()
        self.messages.setReadOnly(True)
        self.messages.document().setDefaultFont(font)
        edit_pane.layout().addWidget(self.messages)

        split.addWidget(edit_pane)

        self.layout().addWidget(split)

    @Slot()
    def compilePDL(self):
        self.messages.appendPlainText('------------')

        pdl_text = self.editor.toPlainText()

        try:
            parser = top.Parser([pdl_text], 's')
            plumb = parser.make_engine()
        except Exception as e:
            self.messages.appendPlainText(
                'Error encountered in PDL compilation:')
            self.messages.appendPlainText(str(e))
            scrollbar = self.messages.verticalScrollBar()
            scrollbar.setValue(scrollbar.maximum())
            return

        if not plumb.is_valid():
            self.messages.appendPlainText('Plumbing engine is invalid:')
            error_str = str('\n'.join(
                [e.error_message for e in plumb.error_set]))
            self.messages.appendPlainText(error_str)
            scrollbar = self.messages.verticalScrollBar()
            scrollbar.setValue(scrollbar.maximum())
            return

        self.messages.appendPlainText('PDL compilation successful')
        scrollbar = self.messages.verticalScrollBar()
        scrollbar.setValue(scrollbar.maximum())

        self.vis_area.visualizer.uploadEngineInstance(plumb)
Example #19
0
class DLPPrinterGUI(QWidget):

    closing_window_event = Signal()
    spinboxValueChanged = Signal(float)

    def __init__(self,
                 dlp_controller=None,
                 parent=None,
                 printer_setup='BOTTOM-UP'):
        QWidget.__init__(self, parent)
        if dlp_controller:
            self.dlp_controller = dlp_controller
        else:
            self.dlp_controller = DLPMainController(printer_setup)
        self.dlp_controller.block_parameters_signal.connect(
            self.block_parameters_signals)
        self.dlp_controller.reactivate_parameters_signal.connect(
            self.reactivate_parameters_signals)
        self.dlp_controller.motor_changed_signal.connect(
            self.update_motor_parameters)
        self.closing_window_event.connect(self.dlp_controller.close_projector)
        self.parent = parent
        self.main_layout = QHBoxLayout()
        self.__init_widget__()
        self.setLayout(self.main_layout)

    def __init_widget__(self):
        self.__left_widget = QWidget()
        self.__left_widget.setSizePolicy(QSizePolicy.Maximum,
                                         QSizePolicy.MinimumExpanding)
        self.__right_widget = QWidget()
        self.__right_widget.setSizePolicy(QSizePolicy.MinimumExpanding,
                                          QSizePolicy.MinimumExpanding)
        self.__init_printer_options_widget__(self.__left_widget)
        self.__init_projector_widget__(self.__left_widget)
        self.__init_support_widget__(self.__left_widget)
        self.__init_features_widget__(self.__left_widget)
        self.__init_advanced_features_widget__(self.__left_widget)
        # self.__init_expected_time_widget__(self.__left_widget)
        self.__left_layout = QGridLayout()
        self.__left_layout.addWidget(self.__printer_options_widget, 0, 0, 1, 2)
        self.__left_layout.addWidget(self.__projector_widget, 1, 0, 1, 2)
        self.__left_layout.addWidget(self.__support_widget, 2, 0, 1, 1)
        self.__left_layout.addWidget(self.__features_widget, 2, 1, 1, 1)
        self.__left_layout.addWidget(self.__advanced_widget, 3, 0, 1, 2)
        # self.__left_layout.addWidget(self.__expected_time_widget, 4,0)
        self.__left_widget.setLayout(self.__left_layout)
        self.__left_widget.show()
        self.__init_start_stop_widget__(self.__right_widget)
        self.__init_preview_widget__(self.__right_widget)
        self.__init_console_widget__(self.__right_widget)
        self.__init_username_jobname_widget__()
        self.__right_layout = QVBoxLayout()
        self.__right_layout.addWidget(self.__start_stop_widget)
        self.__right_layout.addWidget(self.__username_jobname_widget)
        self.__right_layout.addWidget(self.__preview_widget)
        self.__right_layout.addWidget(self.__console_widget)
        self.__right_widget.setLayout(self.__right_layout)
        #        print(self.__left_layout.sizeHint(), self.__right_layout.sizeHint())
        self.main_layout.addWidget(self.__left_widget)
        self.main_layout.addWidget(self.__right_widget)

    def __init_printer_options_widget__(self, parent=None):
        self.__printer_options_widget = QGroupBox("Printer Options", parent)
        # self.__printer_options_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        port_label = QLabel("Port:", self.__printer_options_widget)
        self.port_list = MyQComboBox(self.__printer_options_widget)
        self.port_list.addItems(self.dlp_controller.available_ports())
        self.port_list.currentIndexChanged.connect(
            self.dlp_controller.select_port)
        self.port_list.combo_box_clicked.connect(self.update_port_list)
        connect_button = QPushButton("Connect", self.__printer_options_widget)
        connect_button.clicked.connect(self.dlp_controller.connect_printer)
        disconnect_button = QPushButton("Disconnect",
                                        self.__printer_options_widget)
        disconnect_button.clicked.connect(
            self.dlp_controller.disconnect_printer)
        reset_button = QPushButton("Reset", self.__printer_options_widget)
        reset_button.clicked.connect(self.dlp_controller.reset_printer)
        move_button = QPushButton("Move Building Plate",
                                  self.__printer_options_widget)
        self.move_edit = MyDiscreteStepsSpinBox(
            self.dlp_controller.get_step_length_microns() / 1000.0,
            self.__printer_options_widget)
        self.move_edit.setSuffix("mm")
        self.move_edit.setMaximum(1000)
        self.move_edit.setMinimum(-1000)
        self.move_edit.setDecimals(6)
        self.move_edit.my_value_changed_signal.connect(
            self.dlp_controller.update_building_plate_distance)
        move_button.clicked.connect(self.dlp_controller.move_building_plate)
        set_origin_button = QPushButton("Set Building Plate Origin",
                                        self.__printer_options_widget)
        set_origin_button.clicked.connect(
            self.dlp_controller.set_building_plate_origin)
        home_button = QPushButton("Home Building Plate",
                                  self.__printer_options_widget)
        home_button.clicked.connect(self.dlp_controller.home_building_plate)
        origin_button = QPushButton("Send Building Plate to Origin",
                                    self.__printer_options_widget)
        origin_button.clicked.connect(
            self.dlp_controller.move_building_plate_to_origin)
        options_layout = QGridLayout(self.__printer_options_widget)
        # options_layout.addWidget(options_label, 0, 0, 1, 5)
        options_layout.addWidget(port_label, 0, 0)
        options_layout.addWidget(self.port_list, 0, 1)
        options_layout.addWidget(connect_button, 0, 2)
        options_layout.addWidget(disconnect_button, 0, 3)
        options_layout.addWidget(reset_button, 0, 4)
        options_layout.addWidget(move_button, 1, 0, 1, 2)
        options_layout.addWidget(self.move_edit, 1, 2)
        options_layout.addWidget(set_origin_button, 1, 3, 1, 2)
        options_layout.addWidget(home_button, 2, 0, 1, 2)
        options_layout.addWidget(origin_button, 2, 2, 1, 2)
        self.__printer_options_widget.setLayout(options_layout)

    def __init_projector_widget__(self, parent=None):
        self.__projector_widget = QGroupBox("Projector Options", parent)
        # self.__projector_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        mirror_x = QCheckBox("Mirror X")
        mirror_x.setChecked(self.dlp_controller.is_horizontal_mirrored())
        mirror_x.toggled.connect(self.dlp_controller.set_horizontal_mirroring)
        mirror_y = QCheckBox("Mirror Y")
        mirror_y.setChecked(self.dlp_controller.is_vertical_mirrored())
        mirror_y.toggled.connect(self.dlp_controller.set_vertical_mirroring)
        start_projector_button = QPushButton("Start Projector",
                                             self.__projector_widget)
        start_projector_button.clicked.connect(
            self.dlp_controller.start_projector)
        project_pattern_button = QPushButton("Project Pattern",
                                             self.__projector_widget)
        project_pattern_button.clicked.connect(
            self.dlp_controller.project_calibration_pattern)
        print_position_button = QPushButton("Print Position",
                                            self.__projector_widget)
        print_position_button.clicked.connect(
            self.dlp_controller.print_motor_position)
        home_projector_button = QPushButton("Home Projector",
                                            self.__projector_widget)
        home_projector_button.clicked.connect(
            self.dlp_controller.home_projector)
        move_projector_button = QPushButton("Move Projector",
                                            self.__projector_widget)
        move_projector_button.clicked.connect(
            self.dlp_controller.move_projector)
        move_projector_edit = QDoubleSpinBox(self.__projector_widget)
        move_projector_edit.setSuffix("mm")
        move_projector_edit.setMaximum(10000)
        move_projector_edit.setMinimum(-10000)
        move_projector_edit.setDecimals(3)
        move_projector_edit.setSingleStep(0.001)
        move_projector_edit.valueChanged.connect(
            self.dlp_controller.update_projector_distance)
        set_amplitude_button = QPushButton("Set Projector Amplitude",
                                           self.__projector_widget)
        set_amplitude_button.clicked.connect(
            self.dlp_controller.set_projector_amplitude)
        set_amplitude_edit = QSpinBox(self.__projector_widget)
        set_amplitude_edit.setMaximum(1000)
        set_amplitude_edit.setMinimum(0)
        set_amplitude_edit.setValue(self.dlp_controller.projector_amplitude)
        set_amplitude_edit.valueChanged.connect(
            self.dlp_controller.update_projector_amplitude)
        lock_unlock_projector_button = QPushButton("Lock/Unlock Projector",
                                                   self.__projector_widget)
        lock_unlock_projector_button.clicked.connect(
            self.dlp_controller.lock_unlock_projector)
        projector_layout = QGridLayout(self.__projector_widget)
        # projector_layout.addWidget(projector_label, 0, 0)
        projector_layout.addWidget(mirror_x, 0, 1)
        projector_layout.addWidget(mirror_y, 0, 2)
        projector_layout.addWidget(start_projector_button, 1, 0, 1, 1)
        projector_layout.addWidget(project_pattern_button, 1, 1, 1, 1)
        projector_layout.addWidget(print_position_button, 1, 2, 1, 1)
        projector_layout.addWidget(home_projector_button, 2, 0, 1, 1)
        projector_layout.addWidget(move_projector_button, 2, 1, 1, 1)
        projector_layout.addWidget(move_projector_edit, 2, 2)
        projector_layout.addWidget(set_amplitude_button, 3, 0, 1, 1)
        projector_layout.addWidget(set_amplitude_edit, 3, 1)
        projector_layout.addWidget(lock_unlock_projector_button, 3, 2, 1, 1)
        self.__projector_widget.setLayout(projector_layout)

    def __init_support_widget__(self, parent=None):
        self.__support_widget = QGroupBox("Support Layers Parameters", parent)
        # self.__support_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        thickness_label = QLabel("Layer Thickness", self.__support_widget)
        self.support_thickness_edit = MyDiscreteStepsSpinBox(
            self.dlp_controller.get_step_length_microns(),
            self.__support_widget)
        self.support_thickness_edit.setSuffix(str('\u03BCm'))
        self.support_thickness_edit.setMaximum(1000000)
        self.support_thickness_edit.setMinimum(0)
        self.support_thickness_edit.setDecimals(3)
        self.support_thickness_edit.my_value_changed_signal.connect(
            self.dlp_controller.set_support_thickness)
        self.support_thickness_edit.setValue(
            self.dlp_controller.support_thickness * 1000)
        exposure_label = QLabel("Exposure Time", self.__support_widget)
        exposure_edit = QDoubleSpinBox(self.__support_widget)
        exposure_edit.setSuffix(str('ms'))
        exposure_edit.setMaximum(10000000)
        exposure_edit.setMinimum(0)
        exposure_edit.setDecimals(1)
        exposure_edit.setSingleStep(0.1)
        exposure_edit.setValue(self.dlp_controller.support_exposure)
        exposure_edit.valueChanged.connect(
            self.dlp_controller.set_support_exposure_time)
        amplitude_label = QLabel("Light Amplitude", self.__support_widget)
        amplitude_edit = QSpinBox(self.__support_widget)
        amplitude_edit.setMaximum(1600)
        amplitude_edit.setMinimum(0)
        amplitude_edit.setSingleStep(1)
        amplitude_edit.setValue(self.dlp_controller.support_amplitude)
        amplitude_edit.valueChanged.connect(
            self.dlp_controller.set_support_amplitude)
        burn_layers_label = QLabel("Burn Layers", self.__support_widget)
        burn_layers_edit = QSpinBox(self.__support_widget)
        burn_layers_edit.setMaximum(1000)
        burn_layers_edit.setMinimum(0)
        burn_layers_edit.setSingleStep(1)
        burn_layers_edit.setValue(self.dlp_controller.support_burn_layers)
        burn_layers_edit.valueChanged.connect(
            self.dlp_controller.set_support_burning_layers)
        burn_exposure_label = QLabel("Burn Exposure", self.__support_widget)
        burn_exposure_edit = QDoubleSpinBox(self.__support_widget)
        burn_exposure_edit.setSuffix(str('ms'))
        burn_exposure_edit.setMaximum(100000)
        burn_exposure_edit.setMinimum(0)
        burn_exposure_edit.setDecimals(1)
        burn_exposure_edit.setSingleStep(0.1)
        burn_exposure_edit.setValue(self.dlp_controller.support_burn_exposure)
        burn_exposure_edit.valueChanged.connect(
            self.dlp_controller.set_support_burning_exposure_time)
        burn_amplitude_label = QLabel("Burn Amplitude", self.__support_widget)
        burn_amplitude_edit = QSpinBox(self.__support_widget)
        burn_amplitude_edit.setMaximum(1600)
        burn_amplitude_edit.setMinimum(0)
        burn_amplitude_edit.setSingleStep(1)
        burn_amplitude_edit.setValue(
            self.dlp_controller.support_burn_amplitude)
        burn_amplitude_edit.valueChanged.connect(
            self.dlp_controller.set_support_burning_amplitude)
        select_layers_button = QPushButton("Select Support Images")
        select_layers_button.clicked.connect(self.load_support_images)
        support_layout = QGridLayout(self.__support_widget)
        support_layout.addWidget(thickness_label, 1, 0)
        support_layout.addWidget(self.support_thickness_edit, 1, 1)
        support_layout.addWidget(exposure_label, 2, 0)
        support_layout.addWidget(exposure_edit, 2, 1)
        support_layout.addWidget(amplitude_label, 3, 0)
        support_layout.addWidget(amplitude_edit, 3, 1)
        support_layout.addWidget(burn_layers_label, 4, 0)
        support_layout.addWidget(burn_layers_edit, 4, 1)
        support_layout.addWidget(burn_exposure_label, 5, 0)
        support_layout.addWidget(burn_exposure_edit, 5, 1)
        support_layout.addWidget(burn_amplitude_label, 6, 0)
        support_layout.addWidget(burn_amplitude_edit, 6, 1)
        support_layout.addWidget(select_layers_button, 7, 0, 1, 2)
        self.__support_widget.setLayout(support_layout)

    def __init_features_widget__(self, parent=None):
        self.__features_widget = QGroupBox("Features Layers Parameters",
                                           parent)
        # self.__features_widget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        thickness_label = QLabel("Layer Thickness", self.__features_widget)
        self.features_thickness_edit = MyDiscreteStepsSpinBox(
            self.dlp_controller.get_step_length_microns(),
            self.__features_widget)
        self.features_thickness_edit.setSuffix(str('\u03BCm'))
        self.features_thickness_edit.setMaximum(1000000)
        self.features_thickness_edit.setMinimum(0)
        self.features_thickness_edit.setDecimals(3)
        self.features_thickness_edit.my_value_changed_signal.connect(
            self.dlp_controller.set_features_thickness)
        self.features_thickness_edit.setValue(
            self.dlp_controller.features_thickness * 1000)
        exposure_label = QLabel("Exposure Time", self.__features_widget)
        exposure_edit = QDoubleSpinBox(self.__features_widget)
        exposure_edit.setSuffix(str('ms'))
        exposure_edit.setMaximum(10000000)
        exposure_edit.setMinimum(0)
        exposure_edit.setDecimals(1)
        exposure_edit.setSingleStep(0.1)
        exposure_edit.setValue(self.dlp_controller.features_exposure)
        exposure_edit.valueChanged.connect(
            self.dlp_controller.set_features_exposure_time)
        amplitude_label = QLabel("Light Amplitude", self.__features_widget)
        amplitude_edit = QSpinBox(self.__features_widget)
        amplitude_edit.setMaximum(1600)
        amplitude_edit.setMinimum(0)
        amplitude_edit.setSingleStep(1)
        amplitude_edit.setValue(self.dlp_controller.features_amplitude)
        amplitude_edit.valueChanged.connect(
            self.dlp_controller.set_features_amplitude)
        burn_layers_label = QLabel("Burn Layers", self.__features_widget)
        burn_layers_edit = QSpinBox(self.__features_widget)
        burn_layers_edit.setMaximum(1000)
        burn_layers_edit.setMinimum(0)
        burn_layers_edit.setSingleStep(1)
        burn_layers_edit.setValue(self.dlp_controller.features_burn_layers)
        burn_layers_edit.valueChanged.connect(
            self.dlp_controller.set_features_burning_layers)
        burn_exposure_label = QLabel("Burn Exposure", self.__features_widget)
        burn_exposure_edit = QDoubleSpinBox(self.__features_widget)
        burn_exposure_edit.setSuffix(str('ms'))
        burn_exposure_edit.setMaximum(100000)
        burn_exposure_edit.setMinimum(0)
        burn_exposure_edit.setDecimals(1)
        burn_exposure_edit.setSingleStep(0.1)
        burn_exposure_edit.setValue(self.dlp_controller.features_burn_exposure)
        burn_exposure_edit.valueChanged.connect(
            self.dlp_controller.set_features_burning_exposure_time)
        burn_amplitude_label = QLabel("Burn Amplitude", self.__features_widget)
        burn_amplitude_edit = QSpinBox(self.__features_widget)
        burn_amplitude_edit.setMaximum(1600)
        burn_amplitude_edit.setMinimum(0)
        burn_amplitude_edit.setSingleStep(1)
        burn_amplitude_edit.setValue(
            self.dlp_controller.features_burn_amplitude)
        burn_amplitude_edit.valueChanged.connect(
            self.dlp_controller.set_features_burning_amplitude)
        select_layers_button = QPushButton("Select Features Images")
        select_layers_button.clicked.connect(self.load_features_images)
        features_layout = QGridLayout(self.__features_widget)
        features_layout.addWidget(thickness_label, 1, 0)
        features_layout.addWidget(self.features_thickness_edit, 1, 1)
        features_layout.addWidget(exposure_label, 2, 0)
        features_layout.addWidget(exposure_edit, 2, 1)
        features_layout.addWidget(amplitude_label, 3, 0)
        features_layout.addWidget(amplitude_edit, 3, 1)
        features_layout.addWidget(burn_layers_label, 4, 0)
        features_layout.addWidget(burn_layers_edit, 4, 1)
        features_layout.addWidget(burn_exposure_label, 5, 0)
        features_layout.addWidget(burn_exposure_edit, 5, 1)
        features_layout.addWidget(burn_amplitude_label, 6, 0)
        features_layout.addWidget(burn_amplitude_edit, 6, 1)
        features_layout.addWidget(select_layers_button, 7, 0, 1, 2)
        self.__features_widget.setLayout(features_layout)

    def __init_advanced_features_widget__(self, parent=None):
        self.__advanced_widget = QGroupBox("Advanced Features Options", parent)
        fixed_layer_check = QCheckBox("Fixed Layer", self.__advanced_widget)
        fixed_layer_check.setChecked(self.dlp_controller.fixed_layer)
        fixed_layer_check.toggled.connect(self.dlp_controller.set_fixed_layer)
        incremental_amplitude_check = QCheckBox("Incremental Amplitude",
                                                self.__advanced_widget)
        incremental_amplitude_check.setChecked(
            self.dlp_controller.incremental_amplitude)
        incremental_amplitude_check.toggled.connect(
            self.dlp_controller.set_incremental_amplitude)
        starting_amplitude_label = QLabel("Starting Amplitude",
                                          self.__advanced_widget)
        starting_amplitude_edit = QSpinBox(self.__advanced_widget)
        starting_amplitude_edit.setMaximum(1000)
        starting_amplitude_edit.setMinimum(0)
        starting_amplitude_edit.setSingleStep(1)
        starting_amplitude_edit.setValue(
            self.dlp_controller.starting_incremental_amplitude)
        starting_amplitude_edit.valueChanged.connect(
            self.dlp_controller.set_starting_incremental_amplitude)
        amplitude_step_label = QLabel("Step Size", self.__advanced_widget)
        amplitude_step_edit = QSpinBox(self.__advanced_widget)
        amplitude_step_edit.setMaximum(1000)
        amplitude_step_edit.setMinimum(0)
        amplitude_step_edit.setSingleStep(1)
        amplitude_step_edit.setValue(
            self.dlp_controller.incremental_step_amplitude)
        amplitude_step_edit.valueChanged.connect(
            self.dlp_controller.set_incremental_step_amplitude)
        incremental_exposure_check = QCheckBox("Incremental Exposure",
                                               self.__advanced_widget)
        incremental_exposure_check.setChecked(
            self.dlp_controller.incremental_exposure)
        incremental_exposure_check.toggled.connect(
            self.dlp_controller.set_incremental_exposure)
        starting_exposure_label = QLabel("Starting Exposure",
                                         self.__advanced_widget)
        starting_exposure_edit = QDoubleSpinBox(self.__advanced_widget)
        starting_exposure_edit.setSuffix(str('ms'))
        starting_exposure_edit.setMaximum(100000)
        starting_exposure_edit.setMinimum(0)
        starting_exposure_edit.setDecimals(1)
        starting_exposure_edit.setSingleStep(0.1)
        starting_exposure_edit.valueChanged.connect(
            self.dlp_controller.set_starting_incremental_exposure)
        starting_exposure_edit.setValue(
            self.dlp_controller.starting_incremental_exposure)
        exposure_step_label = QLabel("Step Size", self.__advanced_widget)
        exposure_step_edit = QDoubleSpinBox(self.__advanced_widget)
        exposure_step_edit.setSuffix(str('ms'))
        exposure_step_edit.setMaximum(100000)
        exposure_step_edit.setMinimum(0)
        exposure_step_edit.setDecimals(1)
        exposure_step_edit.setSingleStep(0.1)
        exposure_step_edit.valueChanged.connect(
            self.dlp_controller.set_incremental_step_exposure)
        exposure_step_edit.setValue(
            self.dlp_controller.incremental_step_exposure)
        incremental_thickness_check = QCheckBox("Incremental Thickness",
                                                self.__advanced_widget)
        incremental_thickness_check.setChecked(
            self.dlp_controller.incremental_thickness)
        incremental_thickness_check.toggled.connect(
            self.dlp_controller.set_incremental_thickness)
        thickness_label = QLabel("Starting Thickness", self.__features_widget)
        self.starting_thickness_edit = MyDiscreteStepsSpinBox(
            self.dlp_controller.get_step_length_microns(),
            self.__features_widget)
        self.starting_thickness_edit.setSuffix(str('\u03BCm'))
        self.starting_thickness_edit.setMaximum(1000000)
        self.starting_thickness_edit.setMinimum(0)
        self.starting_thickness_edit.setDecimals(3)
        self.starting_thickness_edit.my_value_changed_signal.connect(
            self.dlp_controller.set_starting_incremental_thickness)
        self.starting_thickness_edit.setValue(
            self.dlp_controller.starting_incremental_thickness * 1000)
        thickness_step_label = QLabel("Step Size", self.__features_widget)
        self.thickness_step_edit = MyDiscreteStepsSpinBox(
            self.dlp_controller.get_step_length_microns(),
            self.__features_widget)
        self.thickness_step_edit.setSuffix(str('\u03BCm'))
        self.thickness_step_edit.setMaximum(1000000)
        self.thickness_step_edit.setMinimum(0)
        self.thickness_step_edit.setDecimals(3)
        self.thickness_step_edit.my_value_changed_signal.connect(
            self.dlp_controller.set_incremental_step_thickness)
        self.thickness_step_edit.setValue(
            self.dlp_controller.incremental_step_thickness * 1000)
        apply_grayscale_correction_check = QCheckBox("Grayscale Correction",
                                                     self.__advanced_widget)
        apply_grayscale_correction_check.setChecked(
            self.dlp_controller.grayscale_correction)
        apply_grayscale_correction_check.toggled.connect(
            self.dlp_controller.set_grayscale_correction)
        grayscale_parameters_widget = QWidget(self.__features_widget)
        a_parameter_label = QLabel("\u03B1", grayscale_parameters_widget)
        alpha_parameter_edit = QDoubleSpinBox(grayscale_parameters_widget)
        alpha_parameter_edit.setMaximum(1000)
        alpha_parameter_edit.setMinimum(0)
        alpha_parameter_edit.setDecimals(3)
        alpha_parameter_edit.setSingleStep(0.001)
        alpha_parameter_edit.valueChanged.connect(
            self.dlp_controller.set_grayscale_alpha)
        alpha_parameter_edit.setValue(self.dlp_controller.grayscale_alpha)
        beta_parameter_label = QLabel("\u03B2", grayscale_parameters_widget)
        beta_parameter_edit = QDoubleSpinBox(grayscale_parameters_widget)
        beta_parameter_edit.setMaximum(1000)
        beta_parameter_edit.setMinimum(0)
        beta_parameter_edit.setDecimals(3)
        beta_parameter_edit.setSingleStep(0.001)
        beta_parameter_edit.valueChanged.connect(
            self.dlp_controller.set_grayscale_beta)
        beta_parameter_edit.setValue(self.dlp_controller.grayscale_beta)
        gamma_parameter_label = QLabel("\u03B3", grayscale_parameters_widget)
        gamma_parameter_edit = QDoubleSpinBox(grayscale_parameters_widget)
        gamma_parameter_edit.setMaximum(1000)
        gamma_parameter_edit.setMinimum(0)
        gamma_parameter_edit.setDecimals(3)
        gamma_parameter_edit.setSingleStep(0.001)
        gamma_parameter_edit.valueChanged.connect(
            self.dlp_controller.set_grayscale_gamma)
        gamma_parameter_edit.setValue(self.dlp_controller.grayscale_gamma)
        grayscale_parameters_layout = QHBoxLayout(grayscale_parameters_widget)
        grayscale_parameters_layout.addWidget(a_parameter_label)
        grayscale_parameters_layout.addWidget(alpha_parameter_edit)
        grayscale_parameters_layout.addWidget(beta_parameter_label)
        grayscale_parameters_layout.addWidget(beta_parameter_edit)
        grayscale_parameters_layout.addWidget(gamma_parameter_label)
        grayscale_parameters_layout.addWidget(gamma_parameter_edit)
        grayscale_parameters_widget.setLayout(grayscale_parameters_layout)
        advanced_features_layout = QGridLayout(self.__advanced_widget)
        advanced_features_layout.addWidget(incremental_amplitude_check, 1, 0,
                                           1, 2)
        advanced_features_layout.addWidget(fixed_layer_check, 1, 3)
        advanced_features_layout.addWidget(starting_amplitude_label, 2, 0)
        advanced_features_layout.addWidget(starting_amplitude_edit, 2, 1)
        advanced_features_layout.addWidget(amplitude_step_label, 2, 2)
        advanced_features_layout.addWidget(amplitude_step_edit, 2, 3)
        advanced_features_layout.addWidget(incremental_exposure_check, 3, 0, 1,
                                           2)
        advanced_features_layout.addWidget(starting_exposure_label, 4, 0)
        advanced_features_layout.addWidget(starting_exposure_edit, 4, 1)
        advanced_features_layout.addWidget(exposure_step_label, 4, 2)
        advanced_features_layout.addWidget(exposure_step_edit, 4, 3)
        advanced_features_layout.addWidget(incremental_thickness_check, 5, 0,
                                           1, 2)
        advanced_features_layout.addWidget(thickness_label, 6, 0)
        advanced_features_layout.addWidget(self.starting_thickness_edit, 6, 1)
        advanced_features_layout.addWidget(thickness_step_label, 6, 2)
        advanced_features_layout.addWidget(self.thickness_step_edit, 6, 3)
        advanced_features_layout.addWidget(apply_grayscale_correction_check, 7,
                                           0, 1, 2)
        advanced_features_layout.addWidget(grayscale_parameters_widget, 8, 0,
                                           1, 4)
        self.__advanced_widget.setLayout(advanced_features_layout)

    def __init_start_stop_widget__(self, parent=None):
        self.__start_stop_widget = QFrame(parent)
        size = self.__left_layout.sizeHint()
        start_button = QPushButton("START", self.__start_stop_widget)
        start_button.setFixedSize(size.width() / 2, size.height() / 7)
        start_button.clicked.connect(
            self.dlp_controller.starting_printing_process)
        stop_button = QPushButton("STOP", self.__start_stop_widget)
        stop_button.setFixedSize(size.width() / 3, size.height() / 8)
        stop_button.setStyleSheet(
            "QPushButton {background-color: red; border-style: outset; border-width: 2px; "
            "border-radius: 10px; border-color: beige; font: bold 20px; padding: 10px;}"
        )
        stop_button.clicked.connect(self.dlp_controller.stop_printing_process)
        self.__start_stop_widget.setMinimumSize(size.width(),
                                                size.height() / 6)
        start_stop_layout = QGridLayout(self.__start_stop_widget)
        start_stop_layout.addWidget(start_button, 0, 0)
        start_stop_layout.addWidget(stop_button, 0, 1)
        self.__start_stop_widget.setLayout(start_stop_layout)

    def __init_preview_widget__(self, parent=None):
        self.__preview_widget = QLabel(parent)
        size = self.__left_layout.sizeHint()
        self.dlp_controller.display_image_signal.connect(self.preview_image)
        self.__preview_widget.setMinimumSize(size.width(), size.height() / 2.3)
        # self.__preview_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.__preview_widget.setScaledContents(True)
        self.__preview_widget.setStyleSheet(
            "QLabel { background-color : black}")

    def __init_console_widget__(self, parent=None):
        self.__console_widget = QPlainTextEdit(parent)
        self.__console_widget.setReadOnly(True)
        size = self.__left_layout.sizeHint()
        # self.__console_widget.setFixedSize(size.width(), size.height()/3)
        self.__console_widget.setStyleSheet(
            "QPlainTextEdit { background-color : gray}")
        palette = self.__console_widget.palette()
        palette.setColor(QPalette.Text, QColor(255, 255, 255))
        self.__console_widget.setPalette(palette)
        self.dlp_controller.print_text_signal.connect(self.print_to_console)

    def __init_username_jobname_widget__(self, parent=None):
        self.__username_jobname_widget = QFrame(parent)
        self.__username_jobname_widget.setSizePolicy(QSizePolicy.Maximum,
                                                     QSizePolicy.Maximum)
        username_label = QLabel("Username",
                                parent=self.__username_jobname_widget)
        username_edit = QLineEdit(parent=self.__username_jobname_widget)
        username_edit.setText(self.dlp_controller.username)
        username_edit.textChanged.connect(self.dlp_controller.set_username)
        jobname_label = QLabel("Print Job Name",
                               parent=self.__username_jobname_widget)
        jobname_edit = QLineEdit(parent=self.__username_jobname_widget)
        jobname_edit.setText(self.dlp_controller.print_job_name)
        jobname_edit.textChanged.connect(self.dlp_controller.set_printjob_name)
        etc = self.dlp_controller.evaluate_time_estimate()
        self.etc_label = QLabel(
            "ETC: " +
            QDateTime.fromTime_t(etc / 1000.0).toUTC().toString('hh:mm:ss'),
            self.__username_jobname_widget)
        self.dlp_controller.etc_updated_signal.connect(
            self.update_time_estimate)
        username_jobname_layout = QHBoxLayout(self.__username_jobname_widget)
        username_jobname_layout.addWidget(self.etc_label)
        username_jobname_layout.addWidget(username_label)
        username_jobname_layout.addWidget(username_edit)
        username_jobname_layout.addWidget(jobname_label)
        username_jobname_layout.addWidget(jobname_edit)
        self.__username_jobname_widget.setLayout(username_jobname_layout)

    @Slot(QPixmap)
    def preview_image(self, image):
        image = image.scaled(self.__preview_widget.width(),
                             self.__preview_widget.height(),
                             Qt.IgnoreAspectRatio)
        self.__preview_widget.setPixmap(image)

    @Slot(str)
    def print_to_console(self, txt):
        self.__console_widget.appendPlainText(txt)

    @Slot()
    def closeEvent(self, event: QCloseEvent):
        self.closing_window_event.emit()
        event.accept()

    @Slot()
    def load_support_images(self):
        file_names = QFileDialog.getOpenFileNames(
            caption='Select images',
            dir='../',
            filter="Image Files (*.png *.jpg *.bmp)")
        self.dlp_controller.set_support_images(file_names[0])

    @Slot()
    def load_features_images(self):
        file_names = QFileDialog.getOpenFileNames(
            caption='Select images',
            dir='../',
            filter="Image Files (*.png *.jpg *.bmp)")
        self.dlp_controller.set_features_images(file_names[0])

    @Slot()
    def block_parameters_signals(self):
        for widget in self.__left_widget.findChildren(QWidget):
            widget.blockSignals(True)

    @Slot()
    def reactivate_parameters_signals(self):
        for widget in self.__left_widget.findChildren(QWidget):
            widget.blockSignals(False)

    @Slot()
    def update_time_estimate(self, etc_ms):
        self.etc_label.setText(
            "ETC: " +
            QDateTime.fromTime_t(etc_ms / 1000.0).toUTC().toString('hh:mm:ss'))

    @Slot()
    def update_port_list(self):
        self.dlp_controller.update_port_list()
        self.port_list.clear()
        self.port_list.addItems(self.dlp_controller.available_ports())

    @Slot(bool)
    def update_motor_parameters(self, is_changed):
        self.move_edit.set_step_size(
            self.dlp_controller.get_step_length_microns() / 1000.0)
        self.support_thickness_edit.set_step_size(
            self.dlp_controller.get_step_length_microns())
        self.support_thickness_edit.spinbox_is_value_valid(
            self.dlp_controller.support_thickness * 1000)
        self.features_thickness_edit.set_step_size(
            self.dlp_controller.get_step_length_microns())
        self.features_thickness_edit.spinbox_is_value_valid(
            self.dlp_controller.features_thickness * 1000)
        self.starting_thickness_edit.set_step_size(
            self.dlp_controller.get_step_length_microns())
        self.starting_thickness_edit.spinbox_is_value_valid(
            self.dlp_controller.starting_incremental_thickness * 1000)
        self.thickness_step_edit.set_step_size(
            self.dlp_controller.get_step_length_microns())
        self.thickness_step_edit.spinbox_is_value_valid(
            self.dlp_controller.incremental_step_thickness * 1000)
Example #20
0
class MyWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.thread = SerialMonitorThread()
        self.thread.dataReady.connect(self.get_data, Qt.QueuedConnection)
        self.thread.setTerminationEnabled(True)

        #Menu
        self.setPalette(get_verifone_color())

        collapsible = CollapsibleWidget()
        self.init_logging(collapsible)

        self.init_download(collapsible)

        self.init_analyser(collapsible)

        collapsible.add_sections()
        # Scroll Area
        self.createLoggingDisplayLabel()
        self.scrollArea = QScrollArea()
        self.scrollArea.setBackgroundRole(QPalette.Dark)
        self.scrollArea.setWidget(self.text)
        self.scrollArea.setWidgetResizable(True)

        hLayout = QHBoxLayout()
        #hLayout.addLayout(vLayout)
        hLayout.addWidget(collapsible)
        hLayout.addWidget(self.scrollArea)

        self.setLayout(hLayout)

    def init_logging(self, collapsible):

        self.logger = QPushButton("Start Logging", self)
        self.logger.setFont(QFont("Times", 14, QFont.Bold))
        self.logger.clicked.connect(lambda: self.display_log_data())
        self.logger.setStyleSheet("background-color: white")

        #self.filterLayout = QtWidgets.QHBoxLayout()
        self.logFilterLabel = QLabel('Filter', self)
        self.logFilterLabel.setFont(QFont("Times", 14, QFont.Bold))
        self.logFilterLabel.setPalette(get_white_color_text())
        self.logFilterLabel.setFixedWidth(60)
        self.logFilter = QLineEdit(self)
        self.logFilter.setPalette(get_white_color())
        self.logFilter.setStyleSheet("background-color: white")
        self.logFilter.setFixedWidth(200)
        #self.filterLayout.addWidget(self.logFilterLabel, QtCore.Qt.AlignLeft)
        #self.filterLayout.addWidget(self.logFilter, QtCore.Qt.AlignLeft)

        self.serialList = QComboBox()
        ports = get_available_serial_ports()
        if (len(ports) == 1):
            self.serialList.addItem(ports[0])
            self.thread.set_comport(self.serialList.currentText())
        else:
            self.serialList.addItem("Select")
            for port in ports:
                self.serialList.addItem(port)

        self.serialList.currentIndexChanged.connect(
            lambda: self.set_serial_port())
        self.serialList.setStyleSheet("background-color: white")
        self.clear = QPushButton("Clear Log File", self)
        self.clear.setStyleSheet("background-color: white")
        self.clear.setFont(QFont("Times", 14, QFont.Bold))
        self.clear.clicked.connect(lambda: self.clear_data())

        widget = QFrame(collapsible.get_tree())
        widget.setPalette(get_verifone_color())
        title = "Logging"
        self.loggerGrid = QGridLayout(widget)
        self.loggerGrid.addWidget(self.logger, 0, 0, 1, 2)
        self.loggerGrid.addWidget(self.logFilterLabel, 1, 0, 1, 1)
        self.loggerGrid.addWidget(self.logFilter, 1, 1, 1, 1)
        self.loggerGrid.addWidget(self.serialList, 2, 0, 1, 2)
        self.loggerGrid.addWidget(self.clear, 3, 0, 1, 2)

        collapsible.include_section(title, widget)

    def init_download(self, collapsible):
        self.download = QPushButton("Download Package", self)
        self.download.setFont(QFont("Times", 14, QFont.Bold))
        self.download.clicked.connect(lambda: self.send_file())
        self.download.setStyleSheet("background-color: white")

        self.loadDownloadFile = QPushButton("Load File", self)
        self.loadDownloadFile.setFont(QFont("Times", 14, QFont.Bold))
        self.loadDownloadFile.clicked.connect(self.loadFromFile)
        self.loadDownloadFile.setStyleSheet("background-color: white")

        self.downloadFileName = QLineEdit("File name", self)
        self.downloadFileName.setStyleSheet("background-color: white")
        self.downloadFileName.setFixedWidth(300)

        self.downloadAddress = QLineEdit("IP Address", self)
        self.downloadAddress.setStyleSheet("background-color: white")
        self.downloadAddress.setFixedWidth(300)

        self.downloadStatus = QLabel("Download Status", self)
        self.downloadStatus.setStyleSheet(
            "background-color: rgba(3, 169, 229, 0); color : white")
        self.downloadStatus.setFixedWidth(300)
        widget = QFrame(collapsible.get_tree())
        title = "Download"

        self.downloadGrid = QGridLayout(widget)
        self.downloadGrid.addWidget(self.download, 0, 0, 1, 2)
        self.downloadGrid.addWidget(self.loadDownloadFile, 1, 0, 1, 2)
        self.downloadGrid.addWidget(self.downloadFileName, 2, 0, 1, 2)
        self.downloadGrid.addWidget(self.downloadAddress, 3, 0, 1, 2)
        self.downloadGrid.addWidget(self.downloadStatus, 4, 0, 1, 2)
        collapsible.include_section(title, widget)

    def init_analyser(self, collapsible):
        self.performanceData = QPushButton("View Performance Data", self)
        self.performanceData.setFont(QFont("Times", 14, QFont.Bold))
        self.performanceData.clicked.connect(
            lambda: self.display_performance_data())
        self.performanceData.setStyleSheet("background-color: white")

        self.performanceChart = QPushButton("View Performance Chart", self)
        self.performanceChart.setFont(QFont("Times", 14, QFont.Bold))
        self.performanceChart.clicked.connect(
            lambda: self.display_performance_chart())
        self.performanceChart.setStyleSheet("background-color: white")

        widget = QFrame(collapsible.get_tree())
        title = "Analyser"
        self.analyserGrid = QGridLayout(widget)
        self.analyserGrid.addWidget(self.performanceData, 0, 0, 1, 2)
        self.analyserGrid.addWidget(self.performanceChart, 1, 0, 1, 2)
        collapsible.include_section(title, widget)

    def loadFromFile(self):
        fileName, _ = QFileDialog.getOpenFileName(
            self, "Load Package", '', "Download Files (*.tgz);;All Files (*)")

        if not fileName:
            return

        try:
            in_file = open(str(fileName), 'rb')
        except IOError:
            QMessageBox.information(
                self, "Unable to open file",
                "There was an error opening \"%s\"" % fileName)
            return
        in_file.close()
        self.downloadFileName.setText(fileName)

    def createLoggingDisplayLabel(self):
        # Display Area
        self.text = QPlainTextEdit(self)
        self.text.setReadOnly(True)
        self.text.setFont(QFont("Times", 12, QFont.Bold))
        self.text.setTextInteractionFlags(Qt.TextSelectableByMouse
                                          | Qt.TextSelectableByKeyboard)

    def clear_data(self):
        self.text.clear()
        os.remove(logfile_path, dir_fd=None)

    def display_log_data(self):
        #send_file()

        if ('COM' in self.serialList.currentText()):
            self.createLoggingDisplayLabel()
            self.scrollArea.setWidget(self.text)
            self.thread.stop()
            self.thread.start()

            data = get_data_from_file(logfile_path)
            if (len(data) > 0 and data != None):
                self.text.appendPlainText(data)
            self.logger.setDisabled(True)

    def get_data(self, data):
        if (len(data) > 0):
            logFile = open(logfile_path, "a")
            logFile.write(data)
            logFile.close()
            filterText = self.logFilter.text()
            if filterText in data.rstrip():
                self.text.appendPlainText(data.rstrip())
                vbar = self.scrollArea.verticalScrollBar()
                vbar.setValue(vbar.maximum())

    def display_performance_data(self):
        self.thread.stop()
        data = get_data_from_file(logfile_path)
        jsonData = translate_data_to_json(data)
        self.performanceData = DisplayPerformanceData()
        self.performanceData.loadCsv(
            os.path.join(base_log_path, "performance_data.csv"))
        self.scrollArea.setWidget(self.performanceData)
        self.logger.setDisabled(False)

    def display_performance_chart(self):
        self.thread.stop()
        self.scrollArea.setWidget(get_performace_chart())
        self.logger.setDisabled(False)

    def set_serial_port(self):
        self.thread.set_comport(self.serialList.currentText())

    def send_file(self):
        base_path = os.path.join("c:/", "VFI", 'wks',
                                 'global-payment-application', 'GPA', 'output',
                                 'vos2', 'gpa', 'dl.gpa-1.0.0.0-000.tgz')
        fileName = self.downloadFileName.text()
        try:
            in_file = open(str(fileName), 'rb')
        except IOError:
            QMessageBox.information(
                self, "Unable to open file",
                "There was an error opening \"%s\"" % fileName)
            return
        in_file.close()

        load_vos_package_ip('192.168.0.104', fileName, self.downloadStatus)
Example #21
0
class MainWindow(QMainWindow):
    font: QFont
    vertical_layout: QVBoxLayout
    central_widget: QWidget
    text_box: QPlainTextEdit
    recognize_button: QPushButton

    assistant: AssistantInterface

    def __init__(self, assistant: AssistantInterface):
        super().__init__()

        qInitResources()

        self.assistant = assistant

        self.build_layout()
        self.init_handlers()

    def build_layout(self):
        self.setup_window()
        self.setup_styles()
        self.setup_font()

        self.build_central_widget()
        self.build_vertical_layout()
        self.build_text_box()
        self.build_recognize_button()

        QMetaObject.connectSlotsByName(self)

    def setup_window(self):
        window_size = QSize(420, 700)

        self.setObjectName("window")
        self.resize(window_size)
        self.setMinimumSize(window_size)
        self.setMaximumSize(window_size)
        self.setWindowTitle(u"Voice Assistant")
        self.setAutoFillBackground(False)

    def setup_styles(self):
        file = QFile(":/styles/style.css")
        file.open(QFile.ReadOnly)

        byte_array = file.readAll()

        file.close()

        self.setStyleSheet(byte_array.data().decode())

    def setup_font(self):
        self.font = QFont()
        self.font.setFamily(u"Helvetica")
        self.font.setPointSize(18)

    def build_central_widget(self):
        size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        size_policy.setHorizontalStretch(0)
        size_policy.setVerticalStretch(0)

        self.central_widget = QWidget(self)
        self.central_widget.setObjectName(u"central_widget")
        self.central_widget.setSizePolicy(size_policy)

        self.setCentralWidget(self.central_widget)

    def build_vertical_layout(self):
        self.vertical_layout = QVBoxLayout(self.central_widget)
        self.vertical_layout.setObjectName(u"vertical_layout")

    def build_text_box(self):
        text_box_size = QSize(420, 600)

        self.text_box = QPlainTextEdit(self.central_widget)
        self.text_box.setObjectName(u"text_box")
        self.text_box.setMaximumSize(text_box_size)
        self.text_box.setFont(self.font)
        self.text_box.setContextMenuPolicy(Qt.NoContextMenu)
        self.text_box.setUndoRedoEnabled(False)
        self.text_box.setReadOnly(True)
        self.text_box.setPlaceholderText("Waiting for your question...")

        self.vertical_layout.addWidget(self.text_box)

    def build_recognize_button(self):
        button_size = QSize(140, 40)

        self.recognize_button = QPushButton(self.central_widget)
        self.recognize_button.setObjectName(u"recognize_button")
        self.recognize_button.setEnabled(True)
        self.recognize_button.setMinimumSize(button_size)
        self.recognize_button.setMaximumSize(button_size)
        self.recognize_button.setFont(self.font)
        self.recognize_button.setAutoFillBackground(False)
        self.recognize_button.setText("Recognize")
        self.recognize_button.setShortcut("Return")

        self.vertical_layout.addWidget(self.recognize_button, 0,
                                       Qt.AlignHCenter)

    def init_handlers(self):
        self.recognize_button.pressed.connect(self.start_recognition)
        self.assistant.on_wake = self.on_assistant_started
        self.assistant.on_sleep = self.on_assistant_finished
        self.assistant.on_assistant_listen = self.on_recognize_started
        self.assistant.on_user_message = self.on_user_text
        self.assistant.on_assistant_message = self.on_assistant_text

    def on_assistant_started(self):
        self.recognize_button.setEnabled(False)

    def on_assistant_finished(self):
        self.recognize_button.setEnabled(True)
        self.recognize_button.setText("Recognize")

    def on_recognize_started(self):
        self.async_play_sound()
        self.recognize_button.setText("Listening...")

    def on_user_text(self, user_text: str):
        self.recognize_button.setText("Processing...")
        self.append_message(f"[You] {user_text}")

    def on_assistant_text(self, assistant_answer: str):
        signed_text = f"[{self.assistant.get_name()}] {assistant_answer}"
        self.append_message(signed_text)

    def append_message(self, message: str):
        self.text_box.appendPlainText(f"{message}\n")

    def start_recognition(self):
        coroutine = self.assistant.handle()
        asyncio.create_task(coroutine)

    @async_function
    def async_play_sound(self):
        file = QFile(":/sounds/click.mp3")
        file.open(QFile.ReadOnly)

        byte_array = file.readAll()

        file.close()

        with tempfile.NamedTemporaryFile("wb", delete=True) as temp:
            temp.write(byte_array.data())
            playsound(temp.name)

    def closeEvent(self, event: QCloseEvent):
        for task in asyncio.all_tasks():
            task.cancel()

        asyncio.get_running_loop().stop()

    async def start(self):
        self.show()