eric6/Plugins/VcsPlugins/vcsMercurial/HgDialog.py

changeset 7370
5fb53279f2df
parent 7360
9190402e4505
child 7441
f115f4469795
equal deleted inserted replaced
7369:dbeeed55df08 7370:5fb53279f2df
5 5
6 """ 6 """
7 Module implementing a dialog starting a process and showing its output. 7 Module implementing a dialog starting a process and showing its output.
8 """ 8 """
9 9
10 10 from PyQt5.QtCore import Qt, QCoreApplication
11 import os 11 from PyQt5.QtWidgets import QDialog, QDialogButtonBox
12
13 from PyQt5.QtCore import (
14 QProcess, QTimer, pyqtSlot, Qt, QCoreApplication, QProcessEnvironment
15 )
16 from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QLineEdit
17
18 from E5Gui import E5MessageBox
19 12
20 from .Ui_HgDialog import Ui_HgDialog 13 from .Ui_HgDialog import Ui_HgDialog
21 14
22 import Preferences 15 import Preferences
23 import Utilities 16 import Utilities
24 from Globals import strToQByteArray
25 17
26 18
27 class HgDialog(QDialog, Ui_HgDialog): 19 class HgDialog(QDialog, Ui_HgDialog):
28 """ 20 """
29 Class implementing a dialog starting a process and showing its output. 21 Class implementing a dialog starting a process and showing its output.
47 self.setWindowFlags(Qt.Window) 39 self.setWindowFlags(Qt.Window)
48 40
49 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) 41 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
50 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) 42 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
51 43
52 self.process = None
53 self.username = '' 44 self.username = ''
54 self.password = '' 45 self.password = ''
55 if useClient:
56 self.__hgClient = hg.getClient()
57 else:
58 self.__hgClient = None
59 self.vcs = hg 46 self.vcs = hg
60 47
61 self.outputGroup.setTitle(text) 48 self.outputGroup.setTitle(text)
62 49
63 self.show() 50 self.show()
66 def __finish(self): 53 def __finish(self):
67 """ 54 """
68 Private slot called when the process finished or the user pressed 55 Private slot called when the process finished or the user pressed
69 the button. 56 the button.
70 """ 57 """
71 if (
72 self.process is not None and
73 self.process.state() != QProcess.NotRunning
74 ):
75 self.process.terminate()
76 QTimer.singleShot(2000, self.process.kill)
77 self.process.waitForFinished(3000)
78
79 self.inputGroup.setEnabled(False)
80 self.inputGroup.hide()
81
82 self.process = None
83
84 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) 58 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
85 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) 59 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
86 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) 60 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
87 self.buttonBox.button(QDialogButtonBox.Close).setFocus( 61 self.buttonBox.button(QDialogButtonBox.Close).setFocus(
88 Qt.OtherFocusReason) 62 Qt.OtherFocusReason)
101 @param button button that was clicked (QAbstractButton) 75 @param button button that was clicked (QAbstractButton)
102 """ 76 """
103 if button == self.buttonBox.button(QDialogButtonBox.Close): 77 if button == self.buttonBox.button(QDialogButtonBox.Close):
104 self.close() 78 self.close()
105 elif button == self.buttonBox.button(QDialogButtonBox.Cancel): 79 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
106 if self.__hgClient: 80 self.vcs.getClient().cancel()
107 self.__hgClient.cancel()
108 else:
109 self.__finish()
110
111 def __procFinished(self, exitCode, exitStatus):
112 """
113 Private slot connected to the finished signal.
114
115 @param exitCode exit code of the process (integer)
116 @param exitStatus exit status of the process (QProcess.ExitStatus)
117 """
118 self.normal = (exitStatus == QProcess.NormalExit) and (exitCode == 0)
119 self.__finish()
120 81
121 def startProcess(self, args, workingDir=None, showArgs=True, 82 def startProcess(self, args, workingDir=None, showArgs=True,
122 environment=None): 83 environment=None):
123 """ 84 """
124 Public slot used to start the process. 85 Public slot used to start the process.
130 or change for the git process (dict of string and string) 91 or change for the git process (dict of string and string)
131 @return flag indicating a successful start of the process 92 @return flag indicating a successful start of the process
132 """ 93 """
133 self.errorGroup.hide() 94 self.errorGroup.hide()
134 self.normal = False 95 self.normal = False
135 self.intercept = False
136 96
137 self.__hasAddOrDelete = False 97 self.__hasAddOrDelete = False
138 if ( 98 if (
139 args[0] in ["fetch", "qpush", "qpop", "qgoto", "rebase", 99 args[0] in ["fetch", "qpush", "qpop", "qgoto", "rebase",
140 "update", "import", "revert", "graft", "shelve", 100 "update", "import", "revert", "graft", "shelve",
148 108
149 if showArgs: 109 if showArgs:
150 self.resultbox.append(' '.join(args)) 110 self.resultbox.append(' '.join(args))
151 self.resultbox.append('') 111 self.resultbox.append('')
152 112
153 if self.__hgClient is None: 113 out, err = self.vcs.getClient().runcommand(
154 self.process = QProcess() 114 args, output=self.__showOutput, error=self.__showError)
155 if environment: 115
156 env = QProcessEnvironment.systemEnvironment() 116 if err:
157 for key, value in environment.items(): 117 self.__showError(err)
158 env.insert(key, value) 118 if out:
159 self.process.setProcessEnvironment(env) 119 self.__showOutput(out)
160 120
161 self.process.finished.connect(self.__procFinished) 121 self.normal = True
162 self.process.readyReadStandardOutput.connect(self.__readStdout) 122
163 self.process.readyReadStandardError.connect(self.__readStderr) 123 self.__finish()
164 124
165 if workingDir: 125 return True
166 self.process.setWorkingDirectory(workingDir)
167 self.process.start('hg', args)
168 procStarted = self.process.waitForStarted(5000)
169 if not procStarted:
170 self.buttonBox.setFocus()
171 self.inputGroup.setEnabled(False)
172 E5MessageBox.critical(
173 self,
174 self.tr('Process Generation Error'),
175 self.tr(
176 'The process {0} could not be started. '
177 'Ensure, that it is in the search path.'
178 ).format('hg'))
179 else:
180 self.inputGroup.setEnabled(True)
181 self.inputGroup.show()
182 return procStarted
183 else:
184 self.inputGroup.setEnabled(False)
185 self.inputGroup.hide()
186
187 out, err = self.__hgClient.runcommand(
188 args, output=self.__showOutput, error=self.__showError)
189
190 if err:
191 self.__showError(err)
192 if out:
193 self.__showOutput(out)
194
195 self.normal = True
196
197 self.__finish()
198
199 return True
200 126
201 def normalExit(self): 127 def normalExit(self):
202 """ 128 """
203 Public method to check for a normal process termination. 129 Public method to check for a normal process termination.
204 130
212 error messages. 138 error messages.
213 139
214 @return flag indicating normal process termination (boolean) 140 @return flag indicating normal process termination (boolean)
215 """ 141 """
216 return self.normal and self.errors.toPlainText() == "" 142 return self.normal and self.errors.toPlainText() == ""
217
218 def __readStdout(self):
219 """
220 Private slot to handle the readyReadStandardOutput signal.
221
222 It reads the output of the process, formats it and inserts it into
223 the contents pane.
224 """
225 if self.process is not None:
226 s = str(self.process.readAllStandardOutput(),
227 self.vcs.getEncoding(),
228 'replace')
229 self.__showOutput(s)
230 143
231 def __showOutput(self, out): 144 def __showOutput(self, out):
232 """ 145 """
233 Private slot to show some output. 146 Private slot to show some output.
234 147
244 self.__hasAddOrDelete = True 157 self.__hasAddOrDelete = True
245 break 158 break
246 159
247 QCoreApplication.processEvents() 160 QCoreApplication.processEvents()
248 161
249 def __readStderr(self):
250 """
251 Private slot to handle the readyReadStandardError signal.
252
253 It reads the error output of the process and inserts it into the
254 error pane.
255 """
256 if self.process is not None:
257 s = str(self.process.readAllStandardError(),
258 self.vcs.getEncoding(),
259 'replace')
260 self.__showError(s)
261
262 def __showError(self, out): 162 def __showError(self, out):
263 """ 163 """
264 Private slot to show some error. 164 Private slot to show some error.
265 165
266 @param out error to be shown (string) 166 @param out error to be shown (string)
269 self.errors.insertPlainText(Utilities.filterAnsiSequences(out)) 169 self.errors.insertPlainText(Utilities.filterAnsiSequences(out))
270 self.errors.ensureCursorVisible() 170 self.errors.ensureCursorVisible()
271 171
272 QCoreApplication.processEvents() 172 QCoreApplication.processEvents()
273 173
274 def on_passwordCheckBox_toggled(self, isOn):
275 """
276 Private slot to handle the password checkbox toggled.
277
278 @param isOn flag indicating the status of the check box (boolean)
279 """
280 if isOn:
281 self.input.setEchoMode(QLineEdit.Password)
282 else:
283 self.input.setEchoMode(QLineEdit.Normal)
284
285 @pyqtSlot()
286 def on_sendButton_clicked(self):
287 """
288 Private slot to send the input to the Mercurial process.
289 """
290 inputTxt = self.input.text()
291 inputTxt += os.linesep
292
293 if self.passwordCheckBox.isChecked():
294 self.errors.insertPlainText(os.linesep)
295 self.errors.ensureCursorVisible()
296 else:
297 self.errors.insertPlainText(inputTxt)
298 self.errors.ensureCursorVisible()
299
300 self.process.write(strToQByteArray(inputTxt))
301
302 self.passwordCheckBox.setChecked(False)
303 self.input.clear()
304
305 def on_input_returnPressed(self):
306 """
307 Private slot to handle the press of the return key in the input field.
308 """
309 self.intercept = True
310 self.on_sendButton_clicked()
311
312 def keyPressEvent(self, evt):
313 """
314 Protected slot to handle a key press event.
315
316 @param evt the key press event (QKeyEvent)
317 """
318 if self.intercept:
319 self.intercept = False
320 evt.accept()
321 return
322 super(HgDialog, self).keyPressEvent(evt)
323
324 def hasAddOrDelete(self): 174 def hasAddOrDelete(self):
325 """ 175 """
326 Public method to check, if the last action contained an add or delete. 176 Public method to check, if the last action contained an add or delete.
327 177
328 @return flag indicating the presence of an add or delete (boolean) 178 @return flag indicating the presence of an add or delete (boolean)

eric ide

mercurial