Thu, 19 Nov 2020 20:19:55 +0100
Continued implementing pybabel translations support.
# -*- coding: utf-8 -*- # Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a dialog to run a flask command and show its output. """ from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QTimer from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton from E5Gui import E5MessageBox from .Ui_FlaskCommandDialog import Ui_FlaskCommandDialog class FlaskCommandDialog(QDialog, Ui_FlaskCommandDialog): """ Class implementing a dialog to run a flask command and show its output. """ def __init__(self, project, parent=None): """ Constructor @param project reference to the project object @type Project @param parent reference to the parent widget @type QWidget """ super(FlaskCommandDialog, self).__init__(parent) self.setupUi(self) self.__project = project self.__process = None self.successMessage = "" self.errorMessage = "" self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) def startFlaskCommand(self, command, args=None): """ Public method to start a flask command and show its output. @param command flask command to be run @type str @param args list of command line arguments for the command @type list of str @return flag indicating a successful start @rtype bool """ workdir, env = self.__project.prepareRuntimeEnvironment() if env is not None: flaskCommand = self.__project.getFlaskCommand() self.__process = QProcess() self.__process.setProcessEnvironment(env) self.__process.setWorkingDirectory(workdir) self.__process.setProcessChannelMode(QProcess.MergedChannels) self.__process.readyReadStandardOutput.connect(self.__readStdOut) self.__process.finished.connect(self.__processFinished) self.outputEdit.clear() flaskArgs = [command] if args: flaskArgs += args self.__process.start(flaskCommand, flaskArgs) ok = self.__process.waitForStarted(10000) if not ok: E5MessageBox.critical( None, self.tr("Execute Flask Command"), self.tr("""The Flask process could not be started.""")) else: self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Cancel).setFocus( Qt.OtherFocusReason) else: ok = False return ok def startBabelCommand(self, command, args, title, msgSuccess="", msgError=""): """ 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 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 @return flag indicating a successful start @rtype bool """ self.setWindowTitle(title) self.successMessage = msgSuccess self.errorMessage = msgError workdir, _ = self.__project.getApplication() babelCommand = self.__project.getBabelCommand() self.__process = QProcess() self.__process.setWorkingDirectory(workdir) self.__process.setProcessChannelMode(QProcess.MergedChannels) self.__process.readyReadStandardOutput.connect(self.__readStdOut) self.__process.finished.connect(self.__processFinished) self.outputEdit.clear() babelArgs = [command] if args: babelArgs += args self.__process.start(babelCommand, babelArgs) ok = self.__process.waitForStarted(10000) if not ok: E5MessageBox.critical( None, self.tr("Execute PyBabel Command"), self.tr("""The pybabel process could not be started.""")) else: self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Cancel).setFocus( Qt.OtherFocusReason) return ok def closeEvent(self, evt): """ Protected method handling the close event of the dialog. @param evt reference to the close event object @type QCloseEvent """ 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.NormalExit) and (exitCode == 0) self.__cancelProcess() self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) self.buttonBox.button(QDialogButtonBox.Close).setFocus( Qt.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.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.Close): self.close() elif button is self.buttonBox.button(QDialogButtonBox.Cancel): self.__cancelProcess()