ProjectFlask/PyBabelCommandDialog.py

changeset 16
dd3f6bfb85f7
parent 15
3f5c05eb2d5f
diff -r 3f5c05eb2d5f -r dd3f6bfb85f7 ProjectFlask/PyBabelCommandDialog.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProjectFlask/PyBabelCommandDialog.py	Sat Nov 21 17:50:57 2020 +0100
@@ -0,0 +1,202 @@
+# -*- 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 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(PyBabelCommandDialog, self).__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.Close).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
+        self.buttonBox.button(QDialogButtonBox.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.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:
+            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 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.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.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.__argsLists = []
+            self.__cancelProcess()

eric ide

mercurial