ProjectFlask/RunServerDialog.py

changeset 6
d491ccab7343
parent 5
550e5ea385cb
child 9
79094fb72c18
--- a/ProjectFlask/RunServerDialog.py	Tue Nov 10 19:38:00 2020 +0100
+++ b/ProjectFlask/RunServerDialog.py	Wed Nov 11 20:03:21 2020 +0100
@@ -10,95 +10,105 @@
 import re
 
 from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QTimer
-from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton
+from PyQt5.QtGui import QTextCharFormat
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox
 
 from E5Gui import E5MessageBox
+from E5Gui.E5Application import e5App
 
 from .Ui_RunServerDialog import Ui_RunServerDialog
 
+from . import AnsiTools
 
+
+# TODO: should this be placed into the sidebar as a sidebar widget?
 class RunServerDialog(QDialog, Ui_RunServerDialog):
     """
     Class implementing a dialog to run the Flask server.
     """
-    def __init__(self, parent=None):
+    def __init__(self, plugin, parent=None):
         """
         Constructor
         
+        @param plugin reference to the plug-in object
+        @type PluginProjectFlask
         @param parent reference to the parent widget
         @type QWidget
         """
         super(RunServerDialog, self).__init__(parent)
         self.setupUi(self)
         
-        self.__process = None
+        self.__plugin = plugin
         
-        self.__ansiRe = re.compile("(\\x1b\[\d+m)")
+        self.__process = None
+        self.__serverUrl = ""
+        
+        self.__ansiRe = re.compile(r"""(\\x1b\[\d+m)""")
+        
+        self.__urlRe = re.compile(r""" * Running on ([^(]+) \(.*""")
         
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
-        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
         
         self.__defaultTextFormat = self.outputEdit.currentCharFormat()
     
-    def startServer(self, command, workdir, env):
+    def startServer(self, project, development=False):
         """
         Public method to start the Flask server process.
         
-        @param command path of the flask command
-        @type str
-        @param workdir working directory for the Flask server
-        @type str
-        @param env environment for the Flask server process
-        @type QProcessEnvironment
-        @return flag indicating a successful start
+        @param project reference to the project object
+        @type Project
+        @param development flag indicating development mode
+        @type bool
+        @return flag indicating success
         @rtype bool
         """
-        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.__process.start(command, ["run"])
-        ok = self.__process.waitForStarted(10000)
-        if not ok:
-            E5MessageBox.critical(
-                None,
-                self.tr("Run Flask Server"),
-                self.tr("""The Flask server process could not be started."""))
+        workdir, env = project.prepareRuntimeEnvironment(
+            development=development)
+        if env is not None:
+            command = 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)
+            
+            args = ["run"]
+#            if host:
+#                args += ["--host", host]
+#            if port:
+#                args += ["--port", str(port)]
+            
+            self.__process.start(command, args)
+            ok = self.__process.waitForStarted(10000)
+            if not ok:
+                E5MessageBox.critical(
+                    None,
+                    self.tr("Run Flask Server"),
+                    self.tr("""The Flask server process could not be"""
+                            """ started."""))
+            else:
+                self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
+                self.stopServerButton.setEnabled(True)
+                self.stopServerButton.setDefault(True)
         else:
-            self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
-            self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
-            self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
+            ok = False
         
         return ok
     
     def closeEvent(self, evt):
         """
-        Private method handling a close event.
+        Protected method handling a close event.
         
         @param evt reference to the close event
         @type QCloseEvent
         """
-        self.__cancel()
+        self.on_stopServerButton_clicked()
         evt.accept()
     
-    @pyqtSlot(QAbstractButton)
-    def on_buttonBox_clicked(self, button):
-        """
-        Private slot handling button presses.
-        
-        @param button button that was pressed
-        @type QAbstractButton
-        """
-        if button is self.buttonBox.button(QDialogButtonBox.Cancel):
-            self.__cancel()
-        elif button is self.buttonBox.button(QDialogButtonBox.Close):
-            self.close()
-    
     @pyqtSlot()
     def __readStdOut(self):
         """
@@ -106,10 +116,27 @@
         """
         if self.__process is not None:
             out = str(self.__process.readAllStandardOutput(), "utf-8")
+            if not self.__serverUrl:
+                urlMatch = self.__urlRe.search(out)
+                if urlMatch:
+                    self.__serverUrl = urlMatch.group(1)
+                    self.startBrowserButton.setEnabled(True)
+            
             for txt in self.__ansiRe.split(out):
                 if txt.startswith("\x1b["):
-                    # TODO: process ANSI escape sequences for coloring
-                    pass
+                    color = int(txt[2:-1])      # strip off ANSI command parts
+                    if color == 0:
+                        self.outputEdit.setCurrentCharFormat(
+                            self.__defaultTextFormat)
+                    elif 30 <= color <= 37:
+                        brush = AnsiTools.getColor(
+                            self.__plugin.getPreferences("AnsiColorScheme"),
+                            color - 30)
+                        if brush is not None:
+                            charFormat = QTextCharFormat(
+                                self.__defaultTextFormat)
+                            charFormat.setForeground(brush)
+                            self.outputEdit.setCurrentCharFormat(charFormat)
                 else:
                     self.outputEdit.insertPlainText(txt)
     
@@ -128,16 +155,28 @@
         
         self.__process = None
         
-        
+        self.startBrowserButton.setEnabled(False)
+        self.stopServerButton.setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
-        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
         self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
         self.buttonBox.button(QDialogButtonBox.Close).setFocus(
             Qt.OtherFocusReason)
     
     @pyqtSlot()
-    def __cancel(self):
+    def on_stopServerButton_clicked(self):
         """
-        Private slot to cancel the running server.
+        Private slot to stop the running server.
         """
         self.__processFinished()
+    
+    @pyqtSlot()
+    def on_startBrowserButton_clicked(self):
+        """
+        Private slot to start a web browser with the server URL.
+        """
+        if self.__plugin.getPreferences("UseExternalBrowser"):
+            import webbrowser
+            webbrowser.open(self.__serverUrl)
+        else:
+            e5App().getObject("UserInterface").launchHelpViewer(
+                self.__serverUrl)

eric ide

mercurial