eric7/Plugins/VcsPlugins/vcsMercurial/HgServeDialog.py

branch
eric7
changeset 8312
800c432b34c8
parent 8288
809d5d5ac2ba
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog for the Mercurial server.
8 """
9
10 import os
11
12 from PyQt5.QtCore import QProcess, Qt, QSize
13 from PyQt5.QtGui import QTextCursor, QBrush
14 from PyQt5.QtWidgets import (
15 QAction, QToolBar, QPlainTextEdit, QSpinBox, QComboBox
16 )
17
18 from E5Gui.E5Application import e5App
19 from E5Gui import E5MessageBox
20 from E5Gui.E5MainWindow import E5MainWindow
21
22 import UI.PixmapCache
23 import Preferences
24
25 from .HgUtilities import getHgExecutable
26
27
28 class HgServeDialog(E5MainWindow):
29 """
30 Class implementing a dialog for the Mercurial server.
31 """
32 def __init__(self, vcs, path, parent=None):
33 """
34 Constructor
35
36 @param vcs reference to the vcs object
37 @type Hg
38 @param path path of the repository to serve
39 @type str
40 @param parent reference to the parent widget
41 @type QWidget
42 """
43 super().__init__(parent)
44
45 self.vcs = vcs
46 self.__repoPath = path
47
48 self.__styles = ["paper", "coal", "gitweb", "monoblue", "spartan", ]
49
50 self.setWindowTitle(self.tr("Mercurial Server"))
51
52 iconSuffix = "dark" if e5App().usesDarkPalette() else "light"
53
54 self.__startAct = QAction(
55 UI.PixmapCache.getIcon(
56 os.path.join("VcsPlugins", "vcsMercurial", "icons",
57 "startServer-{0}.svg".format(iconSuffix))),
58 self.tr("Start Server"), self)
59 self.__startAct.triggered.connect(self.__startServer)
60 self.__stopAct = QAction(
61 UI.PixmapCache.getIcon(
62 os.path.join("VcsPlugins", "vcsMercurial", "icons",
63 "stopServer-{0}.svg".format(iconSuffix))),
64 self.tr("Stop Server"), self)
65 self.__stopAct.triggered.connect(self.__stopServer)
66 self.__browserAct = QAction(
67 UI.PixmapCache.getIcon("home"),
68 self.tr("Start Browser"), self)
69 self.__browserAct.triggered.connect(self.__startBrowser)
70
71 self.__portSpin = QSpinBox(self)
72 self.__portSpin.setMinimum(2048)
73 self.__portSpin.setMaximum(65535)
74 self.__portSpin.setToolTip(self.tr("Enter the server port"))
75 self.__portSpin.setValue(
76 self.vcs.getPlugin().getPreferences("ServerPort"))
77
78 self.__styleCombo = QComboBox(self)
79 self.__styleCombo.addItems(self.__styles)
80 self.__styleCombo.setToolTip(self.tr("Select the style to use"))
81 self.__styleCombo.setCurrentIndex(self.__styleCombo.findText(
82 self.vcs.getPlugin().getPreferences("ServerStyle")))
83
84 self.__serverToolbar = QToolBar(self.tr("Server"), self)
85 self.__serverToolbar.addAction(self.__startAct)
86 self.__serverToolbar.addAction(self.__stopAct)
87 self.__serverToolbar.addSeparator()
88 self.__serverToolbar.addWidget(self.__portSpin)
89 self.__serverToolbar.addWidget(self.__styleCombo)
90
91 self.__browserToolbar = QToolBar(self.tr("Browser"), self)
92 self.__browserToolbar.addAction(self.__browserAct)
93
94 self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.__serverToolbar)
95 self.addToolBar(Qt.ToolBarArea.TopToolBarArea, self.__browserToolbar)
96
97 self.__log = QPlainTextEdit(self)
98 self.setCentralWidget(self.__log)
99
100 # polish up the dialog
101 self.__startAct.setEnabled(True)
102 self.__stopAct.setEnabled(False)
103 self.__browserAct.setEnabled(False)
104 self.__portSpin.setEnabled(True)
105 self.__styleCombo.setEnabled(True)
106 self.resize(QSize(800, 600).expandedTo(self.minimumSizeHint()))
107
108 self.process = QProcess()
109 self.process.finished.connect(self.__procFinished)
110 self.process.readyReadStandardOutput.connect(self.__readStdout)
111 self.process.readyReadStandardError.connect(self.__readStderr)
112
113 self.cNormalFormat = self.__log.currentCharFormat()
114 self.cErrorFormat = self.__log.currentCharFormat()
115 self.cErrorFormat.setForeground(
116 QBrush(Preferences.getUI("LogStdErrColour")))
117
118 def __startServer(self):
119 """
120 Private slot to start the Mercurial server.
121 """
122 port = self.__portSpin.value()
123 style = self.__styleCombo.currentText()
124
125 exe = getHgExecutable()
126
127 args = self.vcs.initCommand("serve")
128 args.append("-v")
129 args.append("--port")
130 args.append(str(port))
131 args.append("--style")
132 args.append(style)
133
134 self.process.setWorkingDirectory(self.__repoPath)
135
136 self.process.start(exe, args)
137 procStarted = self.process.waitForStarted(5000)
138 if procStarted:
139 self.__startAct.setEnabled(False)
140 self.__stopAct.setEnabled(True)
141 self.__browserAct.setEnabled(True)
142 self.__portSpin.setEnabled(False)
143 self.__styleCombo.setEnabled(False)
144 self.vcs.getPlugin().setPreferences("ServerPort", port)
145 self.vcs.getPlugin().setPreferences("ServerStyle", style)
146 else:
147 E5MessageBox.critical(
148 self,
149 self.tr('Process Generation Error'),
150 self.tr(
151 'The process {0} could not be started. '
152 'Ensure, that it is in the search path.'
153 ).format(exe))
154
155 def __stopServer(self):
156 """
157 Private slot to stop the Mercurial server.
158 """
159 if (
160 self.process is not None and
161 self.process.state() != QProcess.ProcessState.NotRunning
162 ):
163 self.process.terminate()
164 self.process.waitForFinished(5000)
165 if self.process.state() != QProcess.ProcessState.NotRunning:
166 self.process.kill()
167
168 self.__startAct.setEnabled(True)
169 self.__stopAct.setEnabled(False)
170 self.__browserAct.setEnabled(False)
171 self.__portSpin.setEnabled(True)
172 self.__styleCombo.setEnabled(True)
173
174 def __startBrowser(self):
175 """
176 Private slot to start a browser for the served repository.
177 """
178 ui = e5App().getObject("UserInterface")
179 ui.launchHelpViewer(
180 "http://localhost:{0}".format(self.__portSpin.value()))
181
182 def closeEvent(self, e):
183 """
184 Protected slot implementing a close event handler.
185
186 @param e close event
187 @type QCloseEvent
188 """
189 self.__stopServer()
190
191 def __procFinished(self, exitCode, exitStatus):
192 """
193 Private slot connected to the finished signal.
194
195 @param exitCode exit code of the process
196 @type int
197 @param exitStatus exit status of the process
198 @type QProcess.ExitStatus
199 """
200 self.__stopServer()
201
202 def __readStdout(self):
203 """
204 Private slot to handle the readyReadStandardOutput signal.
205
206 It reads the output of the process and inserts it into the log.
207 """
208 if self.process is not None:
209 s = str(self.process.readAllStandardOutput(),
210 self.vcs.getEncoding(), 'replace')
211 self.__appendText(s, False)
212
213 def __readStderr(self):
214 """
215 Private slot to handle the readyReadStandardError signal.
216
217 It reads the error output of the process and inserts it into the log.
218 """
219 if self.process is not None:
220 s = str(self.process.readAllStandardError(),
221 self.vcs.getEncoding(), 'replace')
222 self.__appendText(s, True)
223
224 def __appendText(self, txt, error=False):
225 """
226 Private method to append text to the end.
227
228 @param txt text to insert
229 @type str
230 @param error flag indicating to insert error text
231 @type bool
232 """
233 tc = self.__log.textCursor()
234 tc.movePosition(QTextCursor.MoveOperation.End)
235 self.__log.setTextCursor(tc)
236 if error:
237 self.__log.setCurrentCharFormat(self.cErrorFormat)
238 else:
239 self.__log.setCurrentCharFormat(self.cNormalFormat)
240 self.__log.insertPlainText(txt)
241 self.__log.ensureCursorVisible()

eric ide

mercurial