ProjectFlask/FlaskBabelExtension/PyBabelCommandDialog.py

Wed, 16 Nov 2022 09:41:50 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 16 Nov 2022 09:41:50 +0100
branch
eric7
changeset 75
7a30d96ea9f6
parent 72
4557829a4acf
child 82
bb14c648099b
permissions
-rw-r--r--

Resorted the import statements with isort.

# -*- coding: utf-8 -*-

# Copyright (c) 2020 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to run a flask command and show its output.
"""

from PyQt6.QtCore import QProcess, Qt, QTimer, pyqtSlot
from PyQt6.QtWidgets import QAbstractButton, QDialog, QDialogButtonBox

from eric7.EricWidgets import EricMessageBox

from ..Ui_FlaskCommandDialog import Ui_FlaskCommandDialog


class PyBabelCommandDialog(QDialog, Ui_FlaskCommandDialog):
    """
    Class implementing a dialog to run a flask command and show its output.
    """

    def __init__(self, project, title="", msgSuccess="", msgError="", parent=None):
        """
        Constructor

        @param project reference to the project object
        @type Project
        @param title window title of the dialog
        @type str
        @param msgSuccess success message to be shown
        @type str
        @param msgError message to be shown on error
        @type str
        @param parent reference to the parent widget
        @type QWidget
        """
        super().__init__(parent)
        self.setupUi(self)

        if title:
            self.setWindowTitle(title)

        self.__project = project
        self.__successMessage = msgSuccess
        self.__errorMessage = msgError

        self.__process = None
        self.__argsLists = []
        self.__workdir = ""

        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)

    def startCommand(self, command, args, workdir, clearOutput=True):
        """
        Public method to start a pybabel command and show its output.

        @param command pybabel command to be run
        @type str
        @param args list of command line arguments for the command
        @type list of str
        @param workdir working directory for the command
        @type str
        @param clearOutput flag indicating to clear the output
        @type bool
        @return flag indicating a successful start
        @rtype bool
        """
        babelCommand = self.__project.getBabelCommand()

        self.__process = QProcess()
        self.__process.setWorkingDirectory(workdir)
        self.__process.setProcessChannelMode(QProcess.ProcessChannelMode.MergedChannels)

        self.__process.readyReadStandardOutput.connect(self.__readStdOut)
        self.__process.finished.connect(self.__processFinished)

        if clearOutput:
            self.outputEdit.clear()

        babelArgs = [command]
        if args:
            babelArgs += args

        self.__process.start(babelCommand, babelArgs)
        ok = self.__process.waitForStarted(10000)
        if not ok:
            EricMessageBox.critical(
                None,
                self.tr("Execute PyBabel Command"),
                self.tr("""The pybabel process could not be started."""),
            )
        else:
            self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(
                False
            )
            self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(
                True
            )
            self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(
                True
            )
            self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus(
                Qt.FocusReason.OtherFocusReason
            )

        return ok

    def startBatchCommand(self, argsLists, workdir):
        """
        Public method to start a pybabel command repeatedly with a list of
        arguments and show the output.

        @param argsLists list of command line arguments for the batch commands
        @type list of lists of str
        @param workdir working directory for the command
        @type str
        @return flag indicating a successful start of the first process
        @rtype bool
        """
        self.__argsLists = argsLists[:]
        self.__workdir = workdir

        # start the first process
        args = self.__argsLists.pop(0)
        res = self.startCommand(args[0], args[1:], workdir)
        if not res:
            self.__argsLists = []

        return res

    def closeEvent(self, evt):
        """
        Protected method handling the close event of the dialog.

        @param evt reference to the close event object
        @type QCloseEvent
        """
        self.__argsLists = []
        self.__cancelProcess()
        evt.accept()

    @pyqtSlot()
    def __readStdOut(self):
        """
        Private slot to add the server process output to the output pane.
        """
        if self.__process is not None:
            out = str(self.__process.readAllStandardOutput(), "utf-8")
            self.outputEdit.insertPlainText(out)

    def __processFinished(self, exitCode, exitStatus):
        """
        Private slot connected to the finished signal.

        @param exitCode exit code of the process
        @type int
        @param exitStatus exit status of the process
        @type QProcess.ExitStatus
        """
        normal = exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0
        self.__cancelProcess()

        if self.__argsLists:
            args = self.__argsLists.pop(0)
            self.startCommand(args[0], args[1:], self.__workdir, clearOutput=False)
            return

        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus(
            Qt.FocusReason.OtherFocusReason
        )

        if normal and self.__successMessage:
            self.outputEdit.insertPlainText(self.__successMessage)
        elif not normal and self.__errorMessage:
            self.outputEdit.insertPlainText(self.__errorMessage)

    @pyqtSlot()
    def __cancelProcess(self):
        """
        Private slot to terminate the current process.
        """
        if (
            self.__process is not None
            and self.__process.state() != QProcess.ProcessState.NotRunning
        ):
            self.__process.terminate()
            QTimer.singleShot(2000, self.__process.kill)
            self.__process.waitForFinished(3000)

        self.__process = None

    @pyqtSlot(QAbstractButton)
    def on_buttonBox_clicked(self, button):
        """
        Private slot handling presses of the button box buttons.

        @param button reference to the button been clicked
        @type QAbstractButton
        """
        if button is self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
            self.close()
        elif button is self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
            self.__argsLists = []
            self.__cancelProcess()

eric ide

mercurial