ProjectFlask/RunServerDialog.py

changeset 6
d491ccab7343
parent 5
550e5ea385cb
child 9
79094fb72c18
equal deleted inserted replaced
5:550e5ea385cb 6:d491ccab7343
8 """ 8 """
9 9
10 import re 10 import re
11 11
12 from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QTimer 12 from PyQt5.QtCore import pyqtSlot, Qt, QProcess, QTimer
13 from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QAbstractButton 13 from PyQt5.QtGui import QTextCharFormat
14 from PyQt5.QtWidgets import QDialog, QDialogButtonBox
14 15
15 from E5Gui import E5MessageBox 16 from E5Gui import E5MessageBox
17 from E5Gui.E5Application import e5App
16 18
17 from .Ui_RunServerDialog import Ui_RunServerDialog 19 from .Ui_RunServerDialog import Ui_RunServerDialog
18 20
21 from . import AnsiTools
19 22
23
24 # TODO: should this be placed into the sidebar as a sidebar widget?
20 class RunServerDialog(QDialog, Ui_RunServerDialog): 25 class RunServerDialog(QDialog, Ui_RunServerDialog):
21 """ 26 """
22 Class implementing a dialog to run the Flask server. 27 Class implementing a dialog to run the Flask server.
23 """ 28 """
24 def __init__(self, parent=None): 29 def __init__(self, plugin, parent=None):
25 """ 30 """
26 Constructor 31 Constructor
27 32
33 @param plugin reference to the plug-in object
34 @type PluginProjectFlask
28 @param parent reference to the parent widget 35 @param parent reference to the parent widget
29 @type QWidget 36 @type QWidget
30 """ 37 """
31 super(RunServerDialog, self).__init__(parent) 38 super(RunServerDialog, self).__init__(parent)
32 self.setupUi(self) 39 self.setupUi(self)
33 40
41 self.__plugin = plugin
42
34 self.__process = None 43 self.__process = None
44 self.__serverUrl = ""
35 45
36 self.__ansiRe = re.compile("(\\x1b\[\d+m)") 46 self.__ansiRe = re.compile(r"""(\\x1b\[\d+m)""")
47
48 self.__urlRe = re.compile(r""" * Running on ([^(]+) \(.*""")
37 49
38 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) 50 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
39 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
40 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) 51 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
41 52
42 self.__defaultTextFormat = self.outputEdit.currentCharFormat() 53 self.__defaultTextFormat = self.outputEdit.currentCharFormat()
43 54
44 def startServer(self, command, workdir, env): 55 def startServer(self, project, development=False):
45 """ 56 """
46 Public method to start the Flask server process. 57 Public method to start the Flask server process.
47 58
48 @param command path of the flask command 59 @param project reference to the project object
49 @type str 60 @type Project
50 @param workdir working directory for the Flask server 61 @param development flag indicating development mode
51 @type str 62 @type bool
52 @param env environment for the Flask server process 63 @return flag indicating success
53 @type QProcessEnvironment
54 @return flag indicating a successful start
55 @rtype bool 64 @rtype bool
56 """ 65 """
57 self.__process = QProcess() 66 workdir, env = project.prepareRuntimeEnvironment(
58 self.__process.setProcessEnvironment(env) 67 development=development)
59 self.__process.setWorkingDirectory(workdir) 68 if env is not None:
60 self.__process.setProcessChannelMode(QProcess.MergedChannels) 69 command = project.getFlaskCommand()
61 70
62 self.__process.readyReadStandardOutput.connect(self.__readStdOut) 71 self.__process = QProcess()
63 self.__process.finished.connect(self.__processFinished) 72 self.__process.setProcessEnvironment(env)
64 73 self.__process.setWorkingDirectory(workdir)
65 self.__process.start(command, ["run"]) 74 self.__process.setProcessChannelMode(QProcess.MergedChannels)
66 ok = self.__process.waitForStarted(10000) 75
67 if not ok: 76 self.__process.readyReadStandardOutput.connect(self.__readStdOut)
68 E5MessageBox.critical( 77 self.__process.finished.connect(self.__processFinished)
69 None, 78
70 self.tr("Run Flask Server"), 79 args = ["run"]
71 self.tr("""The Flask server process could not be started.""")) 80 # if host:
81 # args += ["--host", host]
82 # if port:
83 # args += ["--port", str(port)]
84
85 self.__process.start(command, args)
86 ok = self.__process.waitForStarted(10000)
87 if not ok:
88 E5MessageBox.critical(
89 None,
90 self.tr("Run Flask Server"),
91 self.tr("""The Flask server process could not be"""
92 """ started."""))
93 else:
94 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
95 self.stopServerButton.setEnabled(True)
96 self.stopServerButton.setDefault(True)
72 else: 97 else:
73 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) 98 ok = False
74 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
75 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
76 99
77 return ok 100 return ok
78 101
79 def closeEvent(self, evt): 102 def closeEvent(self, evt):
80 """ 103 """
81 Private method handling a close event. 104 Protected method handling a close event.
82 105
83 @param evt reference to the close event 106 @param evt reference to the close event
84 @type QCloseEvent 107 @type QCloseEvent
85 """ 108 """
86 self.__cancel() 109 self.on_stopServerButton_clicked()
87 evt.accept() 110 evt.accept()
88
89 @pyqtSlot(QAbstractButton)
90 def on_buttonBox_clicked(self, button):
91 """
92 Private slot handling button presses.
93
94 @param button button that was pressed
95 @type QAbstractButton
96 """
97 if button is self.buttonBox.button(QDialogButtonBox.Cancel):
98 self.__cancel()
99 elif button is self.buttonBox.button(QDialogButtonBox.Close):
100 self.close()
101 111
102 @pyqtSlot() 112 @pyqtSlot()
103 def __readStdOut(self): 113 def __readStdOut(self):
104 """ 114 """
105 Private slot to add the server process output to the output pane. 115 Private slot to add the server process output to the output pane.
106 """ 116 """
107 if self.__process is not None: 117 if self.__process is not None:
108 out = str(self.__process.readAllStandardOutput(), "utf-8") 118 out = str(self.__process.readAllStandardOutput(), "utf-8")
119 if not self.__serverUrl:
120 urlMatch = self.__urlRe.search(out)
121 if urlMatch:
122 self.__serverUrl = urlMatch.group(1)
123 self.startBrowserButton.setEnabled(True)
124
109 for txt in self.__ansiRe.split(out): 125 for txt in self.__ansiRe.split(out):
110 if txt.startswith("\x1b["): 126 if txt.startswith("\x1b["):
111 # TODO: process ANSI escape sequences for coloring 127 color = int(txt[2:-1]) # strip off ANSI command parts
112 pass 128 if color == 0:
129 self.outputEdit.setCurrentCharFormat(
130 self.__defaultTextFormat)
131 elif 30 <= color <= 37:
132 brush = AnsiTools.getColor(
133 self.__plugin.getPreferences("AnsiColorScheme"),
134 color - 30)
135 if brush is not None:
136 charFormat = QTextCharFormat(
137 self.__defaultTextFormat)
138 charFormat.setForeground(brush)
139 self.outputEdit.setCurrentCharFormat(charFormat)
113 else: 140 else:
114 self.outputEdit.insertPlainText(txt) 141 self.outputEdit.insertPlainText(txt)
115 142
116 @pyqtSlot() 143 @pyqtSlot()
117 def __processFinished(self): 144 def __processFinished(self):
126 QTimer.singleShot(2000, self.__process.kill) 153 QTimer.singleShot(2000, self.__process.kill)
127 self.__process.waitForFinished(3000) 154 self.__process.waitForFinished(3000)
128 155
129 self.__process = None 156 self.__process = None
130 157
131 158 self.startBrowserButton.setEnabled(False)
159 self.stopServerButton.setEnabled(False)
132 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) 160 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
133 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
134 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) 161 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
135 self.buttonBox.button(QDialogButtonBox.Close).setFocus( 162 self.buttonBox.button(QDialogButtonBox.Close).setFocus(
136 Qt.OtherFocusReason) 163 Qt.OtherFocusReason)
137 164
138 @pyqtSlot() 165 @pyqtSlot()
139 def __cancel(self): 166 def on_stopServerButton_clicked(self):
140 """ 167 """
141 Private slot to cancel the running server. 168 Private slot to stop the running server.
142 """ 169 """
143 self.__processFinished() 170 self.__processFinished()
171
172 @pyqtSlot()
173 def on_startBrowserButton_clicked(self):
174 """
175 Private slot to start a web browser with the server URL.
176 """
177 if self.__plugin.getPreferences("UseExternalBrowser"):
178 import webbrowser
179 webbrowser.open(self.__serverUrl)
180 else:
181 e5App().getObject("UserInterface").launchHelpViewer(
182 self.__serverUrl)

eric ide

mercurial