diff -r 550e5ea385cb -r d491ccab7343 ProjectFlask/RunServerDialog.py --- 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)