ProjectPyramid/PyramidDialog.py

branch
eric7
changeset 159
d4e7f5a389e6
parent 156
62170c2682a3
child 160
41b23683d5a1
equal deleted inserted replaced
158:24582cac737e 159:d4e7f5a389e6
21 21
22 22
23 class PyramidDialog(QDialog, Ui_PyramidDialog): 23 class PyramidDialog(QDialog, Ui_PyramidDialog):
24 """ 24 """
25 Class implementing a dialog starting a process and showing its output. 25 Class implementing a dialog starting a process and showing its output.
26 26
27 It starts a QProcess and displays a dialog that 27 It starts a QProcess and displays a dialog that
28 shows the output of the process. The dialog is modal, 28 shows the output of the process. The dialog is modal,
29 which causes a synchronized execution of the process. 29 which causes a synchronized execution of the process.
30 """ 30 """
31 def __init__(self, text, fixed=False, linewrap=True, 31
32 msgSuccess=None, msgError=None, 32 def __init__(
33 combinedOutput=False, parent=None): 33 self,
34 text,
35 fixed=False,
36 linewrap=True,
37 msgSuccess=None,
38 msgError=None,
39 combinedOutput=False,
40 parent=None,
41 ):
34 """ 42 """
35 Constructor 43 Constructor
36 44
37 @param text text to be shown by the label 45 @param text text to be shown by the label
38 @type str 46 @type str
39 @param fixed flag indicating a fixed font should be used 47 @param fixed flag indicating a fixed font should be used
40 @type bool 48 @type bool
41 @param linewrap flag indicating to wrap long lines 49 @param linewrap flag indicating to wrap long lines
50 @param parent parent widget 58 @param parent parent widget
51 @type QWidget 59 @type QWidget
52 """ 60 """
53 super().__init__(parent) 61 super().__init__(parent)
54 self.setupUi(self) 62 self.setupUi(self)
55 63
56 self.buttonBox.button( 64 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
57 QDialogButtonBox.StandardButton.Close).setEnabled(False) 65 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
58 self.buttonBox.button( 66
59 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
60
61 self.__proc = None 67 self.__proc = None
62 self.__argsLists = [] 68 self.__argsLists = []
63 self.__workingDir = None 69 self.__workingDir = None
64 self.__msgSuccess = msgSuccess 70 self.__msgSuccess = msgSuccess
65 self.__msgError = msgError 71 self.__msgError = msgError
66 self.__combinedOutput = combinedOutput 72 self.__combinedOutput = combinedOutput
67 self.__batchMode = False 73 self.__batchMode = False
68 74
69 self.outputGroup.setTitle(text) 75 self.outputGroup.setTitle(text)
70 76
71 if fixed: 77 if fixed:
72 if isWindowsPlatform(): 78 if isWindowsPlatform():
73 self.resultbox.setFontFamily("Lucida Console") 79 self.resultbox.setFontFamily("Lucida Console")
74 elif isMacPlatform(): 80 elif isMacPlatform():
75 self.resultbox.setFontFamily("Menlo") 81 self.resultbox.setFontFamily("Menlo")
76 else: 82 else:
77 self.resultbox.setFontFamily("Monospace") 83 self.resultbox.setFontFamily("Monospace")
78 84
79 if not linewrap: 85 if not linewrap:
80 self.resultbox.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) 86 self.resultbox.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
81 87
82 self.show() 88 self.show()
83 QCoreApplication.processEvents() 89 QCoreApplication.processEvents()
84 90
85 def finish(self): 91 def finish(self):
86 """ 92 """
87 Public slot called when the process finished or the user pressed the 93 Public slot called when the process finished or the user pressed the
88 button. 94 button.
89 """ 95 """
90 if ( 96 if (
91 self.__proc is not None and 97 self.__proc is not None
92 self.__proc.state() != QProcess.ProcessState.NotRunning 98 and self.__proc.state() != QProcess.ProcessState.NotRunning
93 ): 99 ):
94 self.__proc.terminate() 100 self.__proc.terminate()
95 QTimer.singleShot(2000, self.__proc.kill) 101 QTimer.singleShot(2000, self.__proc.kill)
96 self.__proc.waitForFinished(3000) 102 self.__proc.waitForFinished(3000)
97 103
98 self.inputGroup.setEnabled(False) 104 self.inputGroup.setEnabled(False)
99 self.inputGroup.hide() 105 self.inputGroup.hide()
100 106
101 self.__proc = None 107 self.__proc = None
102 108
103 self.buttonBox.button( 109 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
104 QDialogButtonBox.StandardButton.Close).setEnabled(True) 110 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
105 self.buttonBox.button( 111 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
106 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 112 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus(
107 self.buttonBox.button( 113 Qt.FocusReason.OtherFocusReason
108 QDialogButtonBox.StandardButton.Close).setDefault(True) 114 )
109 self.buttonBox.button( 115
110 QDialogButtonBox.StandardButton.Close).setFocus(
111 Qt.FocusReason.OtherFocusReason)
112
113 if self.__argsLists: 116 if self.__argsLists:
114 args = self.__argsLists.pop(0)[:] 117 args = self.__argsLists.pop(0)[:]
115 self.startProcess(args[0], args[1:], self.__workingDir) 118 self.startProcess(args[0], args[1:], self.__workingDir)
116 119
117 def on_buttonBox_clicked(self, button): 120 def on_buttonBox_clicked(self, button):
118 """ 121 """
119 Private slot called by a button of the button box clicked. 122 Private slot called by a button of the button box clicked.
120 123
121 @param button button that was clicked 124 @param button button that was clicked
122 @type QAbstractButton 125 @type QAbstractButton
123 """ 126 """
124 if button == self.buttonBox.button( 127 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
125 QDialogButtonBox.StandardButton.Close
126 ):
127 self.close() 128 self.close()
128 elif button == self.buttonBox.button( 129 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
129 QDialogButtonBox.StandardButton.Cancel
130 ):
131 self.finish() 130 self.finish()
132 131
133 def __procFinished(self, exitCode, exitStatus): 132 def __procFinished(self, exitCode, exitStatus):
134 """ 133 """
135 Private slot connected to the finished signal. 134 Private slot connected to the finished signal.
136 135
137 @param exitCode exit code of the process 136 @param exitCode exit code of the process
138 @type int 137 @type int
139 @param exitStatus exit status of the process 138 @param exitStatus exit status of the process
140 @type QProcess.ExitStatus 139 @type QProcess.ExitStatus
141 """ 140 """
142 self.normal = ( 141 self.normal = exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0
143 exitStatus == QProcess.ExitStatus.NormalExit and
144 exitCode == 0
145 )
146 self.finish() 142 self.finish()
147 143
148 if self.normal and self.__msgSuccess: 144 if self.normal and self.__msgSuccess:
149 self.resultbox.insertPlainText(self.__msgSuccess) 145 self.resultbox.insertPlainText(self.__msgSuccess)
150 elif not self.normal and self.__msgError: 146 elif not self.normal and self.__msgError:
151 self.resultbox.insertPlainText(self.__msgError) 147 self.resultbox.insertPlainText(self.__msgError)
152 self.resultbox.ensureCursorVisible() 148 self.resultbox.ensureCursorVisible()
153 149
154 def startProcess(self, command, args, workingDir=None, showArgs=True): 150 def startProcess(self, command, args, workingDir=None, showArgs=True):
155 """ 151 """
156 Public slot used to start the process. 152 Public slot used to start the process.
157 153
158 @param command command to start 154 @param command command to start
159 @type str 155 @type str
160 @param args list of arguments for the process 156 @param args list of arguments for the process
161 @type list of str 157 @type list of str
162 @param workingDir working directory for the process 158 @param workingDir working directory for the process
167 @rtype bool 163 @rtype bool
168 """ 164 """
169 self.errorGroup.hide() 165 self.errorGroup.hide()
170 self.normal = False 166 self.normal = False
171 self.intercept = False 167 self.intercept = False
172 168
173 self.buttonBox.button( 169 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
174 QDialogButtonBox.StandardButton.Close).setEnabled(False) 170 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
175 self.buttonBox.button( 171 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
176 QDialogButtonBox.StandardButton.Cancel).setEnabled(True) 172 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setFocus(
177 self.buttonBox.button( 173 Qt.FocusReason.OtherFocusReason
178 QDialogButtonBox.StandardButton.Cancel).setDefault(True) 174 )
179 self.buttonBox.button( 175
180 QDialogButtonBox.StandardButton.Cancel).setFocus(
181 Qt.FocusReason.OtherFocusReason)
182
183 if self.__batchMode: 176 if self.__batchMode:
184 self.resultbox.append(80 * '#') 177 self.resultbox.append(80 * "#")
185 178
186 if showArgs: 179 if showArgs:
187 self.resultbox.append(command + ' ' + ' '.join(args)) 180 self.resultbox.append(command + " " + " ".join(args))
188 self.resultbox.append('') 181 self.resultbox.append("")
189 182
190 self.__proc = QProcess() 183 self.__proc = QProcess()
191 if self.__combinedOutput: 184 if self.__combinedOutput:
192 self.__proc.setProcessChannelMode( 185 self.__proc.setProcessChannelMode(
193 QProcess.ProcessChannelMode.MergedChannels) 186 QProcess.ProcessChannelMode.MergedChannels
194 187 )
188
195 self.__proc.finished.connect(self.__procFinished) 189 self.__proc.finished.connect(self.__procFinished)
196 self.__proc.readyReadStandardOutput.connect(self.__readStdout) 190 self.__proc.readyReadStandardOutput.connect(self.__readStdout)
197 self.__proc.readyReadStandardError.connect(self.__readStderr) 191 self.__proc.readyReadStandardError.connect(self.__readStderr)
198 192
199 if workingDir: 193 if workingDir:
200 self.__proc.setWorkingDirectory(workingDir) 194 self.__proc.setWorkingDirectory(workingDir)
201 self.__proc.start(command, args) 195 self.__proc.start(command, args)
202 procStarted = self.__proc.waitForStarted() 196 procStarted = self.__proc.waitForStarted()
203 if not procStarted: 197 if not procStarted:
204 self.buttonBox.setFocus() 198 self.buttonBox.setFocus()
205 self.inputGroup.setEnabled(False) 199 self.inputGroup.setEnabled(False)
206 EricMessageBox.critical( 200 EricMessageBox.critical(
207 self, 201 self,
208 self.tr('Process Generation Error'), 202 self.tr("Process Generation Error"),
209 self.tr( 203 self.tr(
210 'The process {0} could not be started. ' 204 "The process {0} could not be started. "
211 'Ensure, that it is in the search path.' 205 "Ensure, that it is in the search path."
212 ).format(command)) 206 ).format(command),
207 )
213 else: 208 else:
214 self.inputGroup.setEnabled(True) 209 self.inputGroup.setEnabled(True)
215 self.inputGroup.show() 210 self.inputGroup.show()
216 return procStarted 211 return procStarted
217 212
218 def startBatchProcesses(self, argsLists, workingDir=None): 213 def startBatchProcesses(self, argsLists, workingDir=None):
219 """ 214 """
220 Public slot used to start a batch of processes. 215 Public slot used to start a batch of processes.
221 216
222 @param argsLists list of lists of arguments for the processes 217 @param argsLists list of lists of arguments for the processes
223 @type list of list of str 218 @type list of list of str
224 @param workingDir working directory for the process 219 @param workingDir working directory for the process
225 @type str 220 @type str
226 @return flag indicating a successful start of the first process 221 @return flag indicating a successful start of the first process
227 @rtype bool 222 @rtype bool
228 """ 223 """
229 self.__argsLists = argsLists[:] 224 self.__argsLists = argsLists[:]
230 self.__workingDir = workingDir 225 self.__workingDir = workingDir
231 self.__batchMode = True 226 self.__batchMode = True
232 227
233 # start the first process 228 # start the first process
234 args = self.__argsLists.pop(0)[:] 229 args = self.__argsLists.pop(0)[:]
235 res = self.startProcess(args[0], args[1:], self.__workingDir) 230 res = self.startProcess(args[0], args[1:], self.__workingDir)
236 if not res: 231 if not res:
237 self.__argsLists = [] 232 self.__argsLists = []
238 233
239 return res 234 return res
240 235
241 def normalExit(self): 236 def normalExit(self):
242 """ 237 """
243 Public method to check for a normal process termination. 238 Public method to check for a normal process termination.
244 239
245 @return flag indicating normal process termination 240 @return flag indicating normal process termination
246 @rtype bool 241 @rtype bool
247 """ 242 """
248 return self.normal 243 return self.normal
249 244
250 def normalExitWithoutErrors(self): 245 def normalExitWithoutErrors(self):
251 """ 246 """
252 Public method to check for a normal process termination without 247 Public method to check for a normal process termination without
253 error messages. 248 error messages.
254 249
255 @return flag indicating normal process termination 250 @return flag indicating normal process termination
256 @rtype bool 251 @rtype bool
257 """ 252 """
258 return self.normal and self.errors.toPlainText() == "" 253 return self.normal and self.errors.toPlainText() == ""
259 254
260 def __readStdout(self): 255 def __readStdout(self):
261 """ 256 """
262 Private slot to handle the readyReadStandardOutput signal. 257 Private slot to handle the readyReadStandardOutput signal.
263 258
264 It reads the output of the process, formats it and inserts it into 259 It reads the output of the process, formats it and inserts it into
265 the contents pane. 260 the contents pane.
266 """ 261 """
267 if self.__proc is not None: 262 if self.__proc is not None:
268 out = str(self.__proc.readAllStandardOutput(), 263 out = str(
269 Preferences.getSystem("IOEncoding"), 264 self.__proc.readAllStandardOutput(),
270 'replace') 265 Preferences.getSystem("IOEncoding"),
266 "replace",
267 )
271 self.resultbox.insertPlainText(out) 268 self.resultbox.insertPlainText(out)
272 self.resultbox.ensureCursorVisible() 269 self.resultbox.ensureCursorVisible()
273 270
274 QCoreApplication.processEvents() 271 QCoreApplication.processEvents()
275 272
276 def __readStderr(self): 273 def __readStderr(self):
277 """ 274 """
278 Private slot to handle the readyReadStandardError signal. 275 Private slot to handle the readyReadStandardError signal.
279 276
280 It reads the error output of the process and inserts it into the 277 It reads the error output of the process and inserts it into the
281 error pane. 278 error pane.
282 """ 279 """
283 if self.__proc is not None: 280 if self.__proc is not None:
284 err = str(self.__proc.readAllStandardError(), 281 err = str(
285 Preferences.getSystem("IOEncoding"), 282 self.__proc.readAllStandardError(),
286 'replace') 283 Preferences.getSystem("IOEncoding"),
284 "replace",
285 )
287 self.errorGroup.show() 286 self.errorGroup.show()
288 self.errors.insertPlainText(err) 287 self.errors.insertPlainText(err)
289 self.errors.ensureCursorVisible() 288 self.errors.ensureCursorVisible()
290 289
291 QCoreApplication.processEvents() 290 QCoreApplication.processEvents()
292 291
293 def on_passwordCheckBox_toggled(self, isOn): 292 def on_passwordCheckBox_toggled(self, isOn):
294 """ 293 """
295 Private slot to handle the password checkbox toggled. 294 Private slot to handle the password checkbox toggled.
296 295
297 @param isOn flag indicating the status of the check box 296 @param isOn flag indicating the status of the check box
298 @type bool 297 @type bool
299 """ 298 """
300 if isOn: 299 if isOn:
301 self.input.setEchoMode(QLineEdit.EchoMode.Password) 300 self.input.setEchoMode(QLineEdit.EchoMode.Password)
302 else: 301 else:
303 self.input.setEchoMode(QLineEdit.EchoMode.Normal) 302 self.input.setEchoMode(QLineEdit.EchoMode.Normal)
304 303
305 @pyqtSlot() 304 @pyqtSlot()
306 def on_sendButton_clicked(self): 305 def on_sendButton_clicked(self):
307 """ 306 """
308 Private slot to send the input to the subversion process. 307 Private slot to send the input to the subversion process.
309 """ 308 """
310 inputTxt = self.input.text() 309 inputTxt = self.input.text()
311 inputTxt += os.linesep 310 inputTxt += os.linesep
312 311
313 if self.passwordCheckBox.isChecked(): 312 if self.passwordCheckBox.isChecked():
314 self.errors.insertPlainText(os.linesep) 313 self.errors.insertPlainText(os.linesep)
315 self.errors.ensureCursorVisible() 314 self.errors.ensureCursorVisible()
316 else: 315 else:
317 self.resultbox.insertPlainText(inputTxt) 316 self.resultbox.insertPlainText(inputTxt)
318 self.resultbox.ensureCursorVisible() 317 self.resultbox.ensureCursorVisible()
319 318
320 self.__proc.write(strToQByteArray(inputTxt)) 319 self.__proc.write(strToQByteArray(inputTxt))
321 320
322 self.passwordCheckBox.setChecked(False) 321 self.passwordCheckBox.setChecked(False)
323 self.input.clear() 322 self.input.clear()
324 323
325 def on_input_returnPressed(self): 324 def on_input_returnPressed(self):
326 """ 325 """
327 Private slot to handle the press of the return key in the input field. 326 Private slot to handle the press of the return key in the input field.
328 """ 327 """
329 self.intercept = True 328 self.intercept = True
330 self.on_sendButton_clicked() 329 self.on_sendButton_clicked()
331 330
332 def keyPressEvent(self, evt): 331 def keyPressEvent(self, evt):
333 """ 332 """
334 Protected slot to handle a key press event. 333 Protected slot to handle a key press event.
335 334
336 @param evt the key press event 335 @param evt the key press event
337 @type QKeyEvent 336 @type QKeyEvent
338 """ 337 """
339 if self.intercept: 338 if self.intercept:
340 self.intercept = False 339 self.intercept = False

eric ide

mercurial