45 @param parent reference to the parent widget |
50 @param parent reference to the parent widget |
46 @type QWidget |
51 @type QWidget |
47 """ |
52 """ |
48 super().__init__(parent) |
53 super().__init__(parent) |
49 self.setupUi(self) |
54 self.setupUi(self) |
50 |
55 |
51 self.buttonBox.button( |
56 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False) |
52 QDialogButtonBox.StandardButton.Close).setEnabled(False) |
57 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True) |
53 self.buttonBox.button( |
58 |
54 QDialogButtonBox.StandardButton.Cancel).setDefault(True) |
|
55 |
|
56 font = Preferences.getEditorOtherFonts("MonospacedFont") |
59 font = Preferences.getEditorOtherFonts("MonospacedFont") |
57 self.resultbox.setFontFamily(font.family()) |
60 self.resultbox.setFontFamily(font.family()) |
58 self.resultbox.setFontPointSize(font.pointSize()) |
61 self.resultbox.setFontPointSize(font.pointSize()) |
59 self.errors.setFontFamily(font.family()) |
62 self.errors.setFontFamily(font.family()) |
60 self.errors.setFontPointSize(font.pointSize()) |
63 self.errors.setFontPointSize(font.pointSize()) |
61 |
64 |
62 if windowTitle: |
65 if windowTitle: |
63 self.setWindowTitle(windowTitle) |
66 self.setWindowTitle(windowTitle) |
64 if outputTitle: |
67 if outputTitle: |
65 self.outputGroup.setTitle(outputTitle) |
68 self.outputGroup.setTitle(outputTitle) |
66 self.__showProgress = showProgress |
69 self.__showProgress = showProgress |
67 self.progressBar.setVisible(self.__showProgress) |
70 self.progressBar.setVisible(self.__showProgress) |
68 |
71 |
69 self.__process = None |
72 self.__process = None |
70 self.__progressRe = re.compile(r"""(\d{1,3})\s*%""") |
73 self.__progressRe = re.compile(r"""(\d{1,3})\s*%""") |
71 |
74 |
72 self.show() |
75 self.show() |
73 QCoreApplication.processEvents() |
76 QCoreApplication.processEvents() |
74 |
77 |
75 def __finish(self): |
78 def __finish(self): |
76 """ |
79 """ |
77 Private slot called when the process finished or the user pressed |
80 Private slot called when the process finished or the user pressed |
78 the button. |
81 the button. |
79 """ |
82 """ |
80 if ( |
83 if ( |
81 self.__process is not None and |
84 self.__process is not None |
82 self.__process.state() != QProcess.ProcessState.NotRunning |
85 and self.__process.state() != QProcess.ProcessState.NotRunning |
83 ): |
86 ): |
84 self.__process.terminate() |
87 self.__process.terminate() |
85 QTimer.singleShot(2000, self.__process.kill) |
88 QTimer.singleShot(2000, self.__process.kill) |
86 self.__process.waitForFinished(3000) |
89 self.__process.waitForFinished(3000) |
87 |
90 |
88 self.inputGroup.setEnabled(False) |
91 self.inputGroup.setEnabled(False) |
89 self.inputGroup.hide() |
92 self.inputGroup.hide() |
90 |
93 |
91 self.__process = None |
94 self.__process = None |
92 |
95 |
93 self.buttonBox.button( |
96 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True) |
94 QDialogButtonBox.StandardButton.Close).setEnabled(True) |
97 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False) |
95 self.buttonBox.button( |
98 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True) |
96 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) |
99 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus( |
97 self.buttonBox.button( |
100 Qt.FocusReason.OtherFocusReason |
98 QDialogButtonBox.StandardButton.Close).setDefault(True) |
101 ) |
99 self.buttonBox.button( |
102 |
100 QDialogButtonBox.StandardButton.Close).setFocus( |
|
101 Qt.FocusReason.OtherFocusReason) |
|
102 |
|
103 def on_buttonBox_clicked(self, button): |
103 def on_buttonBox_clicked(self, button): |
104 """ |
104 """ |
105 Private slot called by a button of the button box clicked. |
105 Private slot called by a button of the button box clicked. |
106 |
106 |
107 @param button button that was clicked |
107 @param button button that was clicked |
108 @type QAbstractButton |
108 @type QAbstractButton |
109 """ |
109 """ |
110 if button == self.buttonBox.button( |
110 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close): |
111 QDialogButtonBox.StandardButton.Close |
|
112 ): |
|
113 self.close() |
111 self.close() |
114 elif button == self.buttonBox.button( |
112 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel): |
115 QDialogButtonBox.StandardButton.Cancel |
|
116 ): |
|
117 self.statusLabel.setText(self.tr("Process canceled.")) |
113 self.statusLabel.setText(self.tr("Process canceled.")) |
118 self.__finish() |
114 self.__finish() |
119 |
115 |
120 def __procFinished(self, exitCode, exitStatus): |
116 def __procFinished(self, exitCode, exitStatus): |
121 """ |
117 """ |
122 Private slot connected to the finished signal. |
118 Private slot connected to the finished signal. |
123 |
119 |
124 @param exitCode exit code of the process |
120 @param exitCode exit code of the process |
125 @type int |
121 @type int |
126 @param exitStatus exit status of the process |
122 @param exitStatus exit status of the process |
127 @type QProcess.ExitStatus |
123 @type QProcess.ExitStatus |
128 """ |
124 """ |
129 self.__normal = ( |
125 self.__normal = (exitStatus == QProcess.ExitStatus.NormalExit) and ( |
130 (exitStatus == QProcess.ExitStatus.NormalExit) and |
126 exitCode == 0 |
131 (exitCode == 0) |
|
132 ) |
127 ) |
133 if self.__normal: |
128 if self.__normal: |
134 self.statusLabel.setText(self.tr("Process finished successfully.")) |
129 self.statusLabel.setText(self.tr("Process finished successfully.")) |
135 elif exitStatus == QProcess.ExitStatus.CrashExit: |
130 elif exitStatus == QProcess.ExitStatus.CrashExit: |
136 self.statusLabel.setText(self.tr("Process crashed.")) |
131 self.statusLabel.setText(self.tr("Process crashed.")) |
137 else: |
132 else: |
138 self.statusLabel.setText( |
133 self.statusLabel.setText( |
139 self.tr("Process finished with exit code {0}") |
134 self.tr("Process finished with exit code {0}").format(exitCode) |
140 .format(exitCode)) |
135 ) |
141 self.__finish() |
136 self.__finish() |
142 |
137 |
143 def startProcess(self, program, args, workingDir=None, showArgs=True, |
138 def startProcess( |
144 environment=None): |
139 self, program, args, workingDir=None, showArgs=True, environment=None |
|
140 ): |
145 """ |
141 """ |
146 Public slot used to start the process. |
142 Public slot used to start the process. |
147 |
143 |
148 @param program path of the program to be executed |
144 @param program path of the program to be executed |
149 @type str |
145 @type str |
150 @param args list of arguments for the process |
146 @param args list of arguments for the process |
151 @type list of str |
147 @type list of str |
152 @param workingDir working directory for the process |
148 @param workingDir working directory for the process |
160 @rtype bool |
156 @rtype bool |
161 """ |
157 """ |
162 self.errorGroup.hide() |
158 self.errorGroup.hide() |
163 self.__normal = False |
159 self.__normal = False |
164 self.__intercept = False |
160 self.__intercept = False |
165 |
161 |
166 if environment is None: |
162 if environment is None: |
167 environment = {} |
163 environment = {} |
168 |
164 |
169 if showArgs: |
165 if showArgs: |
170 self.resultbox.append(program + ' ' + ' '.join(args)) |
166 self.resultbox.append(program + " " + " ".join(args)) |
171 self.resultbox.append('') |
167 self.resultbox.append("") |
172 |
168 |
173 self.__process = QProcess() |
169 self.__process = QProcess() |
174 if environment: |
170 if environment: |
175 env = QProcessEnvironment.systemEnvironment() |
171 env = QProcessEnvironment.systemEnvironment() |
176 for key, value in environment.items(): |
172 for key, value in environment.items(): |
177 env.insert(key, value) |
173 env.insert(key, value) |
178 self.__process.setProcessEnvironment(env) |
174 self.__process.setProcessEnvironment(env) |
179 |
175 |
180 self.__process.finished.connect(self.__procFinished) |
176 self.__process.finished.connect(self.__procFinished) |
181 self.__process.readyReadStandardOutput.connect(self.__readStdout) |
177 self.__process.readyReadStandardOutput.connect(self.__readStdout) |
182 self.__process.readyReadStandardError.connect(self.__readStderr) |
178 self.__process.readyReadStandardError.connect(self.__readStderr) |
183 |
179 |
184 if workingDir: |
180 if workingDir: |
185 self.__process.setWorkingDirectory(workingDir) |
181 self.__process.setWorkingDirectory(workingDir) |
186 |
182 |
187 self.__process.start(program, args) |
183 self.__process.start(program, args) |
188 procStarted = self.__process.waitForStarted(10000) |
184 procStarted = self.__process.waitForStarted(10000) |
189 if not procStarted: |
185 if not procStarted: |
190 self.buttonBox.setFocus() |
186 self.buttonBox.setFocus() |
191 self.inputGroup.setEnabled(False) |
187 self.inputGroup.setEnabled(False) |
192 EricMessageBox.critical( |
188 EricMessageBox.critical( |
193 self, |
189 self, |
194 self.tr('Process Generation Error'), |
190 self.tr("Process Generation Error"), |
195 self.tr( |
191 self.tr("<p>The process <b>{0}</b> could not be started.</p>").format( |
196 '<p>The process <b>{0}</b> could not be started.</p>' |
192 program |
197 ).format(program)) |
193 ), |
|
194 ) |
198 else: |
195 else: |
199 self.inputGroup.setEnabled(True) |
196 self.inputGroup.setEnabled(True) |
200 self.inputGroup.show() |
197 self.inputGroup.show() |
201 |
198 |
202 return procStarted |
199 return procStarted |
203 |
200 |
204 def normalExit(self): |
201 def normalExit(self): |
205 """ |
202 """ |
206 Public method to check for a normal process termination. |
203 Public method to check for a normal process termination. |
207 |
204 |
208 @return flag indicating normal process termination |
205 @return flag indicating normal process termination |
209 @rtype bool |
206 @rtype bool |
210 """ |
207 """ |
211 return self.__normal |
208 return self.__normal |
212 |
209 |
213 def normalExitWithoutErrors(self): |
210 def normalExitWithoutErrors(self): |
214 """ |
211 """ |
215 Public method to check for a normal process termination without |
212 Public method to check for a normal process termination without |
216 error messages. |
213 error messages. |
217 |
214 |
218 @return flag indicating normal process termination |
215 @return flag indicating normal process termination |
219 @rtype bool |
216 @rtype bool |
220 """ |
217 """ |
221 return self.__normal and self.errors.toPlainText() == "" |
218 return self.__normal and self.errors.toPlainText() == "" |
222 |
219 |
223 def __readStdout(self): |
220 def __readStdout(self): |
224 """ |
221 """ |
225 Private slot to handle the readyReadStandardOutput signal. |
222 Private slot to handle the readyReadStandardOutput signal. |
226 |
223 |
227 It reads the output of the process and inserts it into the |
224 It reads the output of the process and inserts it into the |
228 output pane. |
225 output pane. |
229 """ |
226 """ |
230 if self.__process is not None: |
227 if self.__process is not None: |
231 s = str(self.__process.readAllStandardOutput(), |
228 s = str( |
232 Preferences.getSystem("IOEncoding"), |
229 self.__process.readAllStandardOutput(), |
233 'replace') |
230 Preferences.getSystem("IOEncoding"), |
|
231 "replace", |
|
232 ) |
234 if self.__showProgress: |
233 if self.__showProgress: |
235 match = self.__progressRe.search(s) |
234 match = self.__progressRe.search(s) |
236 if match: |
235 if match: |
237 progress = int(match.group(1)) |
236 progress = int(match.group(1)) |
238 self.progressBar.setValue(progress) |
237 self.progressBar.setValue(progress) |
239 if not s.endswith("\n"): |
238 if not s.endswith("\n"): |
240 s += "\n" |
239 s += "\n" |
241 self.resultbox.insertPlainText(s) |
240 self.resultbox.insertPlainText(s) |
242 self.resultbox.ensureCursorVisible() |
241 self.resultbox.ensureCursorVisible() |
243 |
242 |
244 QCoreApplication.processEvents() |
243 QCoreApplication.processEvents() |
245 |
244 |
246 def __readStderr(self): |
245 def __readStderr(self): |
247 """ |
246 """ |
248 Private slot to handle the readyReadStandardError signal. |
247 Private slot to handle the readyReadStandardError signal. |
249 |
248 |
250 It reads the error output of the process and inserts it into the |
249 It reads the error output of the process and inserts it into the |
251 error pane. |
250 error pane. |
252 """ |
251 """ |
253 if self.__process is not None: |
252 if self.__process is not None: |
254 s = str(self.__process.readAllStandardError(), |
253 s = str( |
255 Preferences.getSystem("IOEncoding"), |
254 self.__process.readAllStandardError(), |
256 'replace') |
255 Preferences.getSystem("IOEncoding"), |
257 |
256 "replace", |
|
257 ) |
|
258 |
258 self.errorGroup.show() |
259 self.errorGroup.show() |
259 self.errors.insertPlainText(s) |
260 self.errors.insertPlainText(s) |
260 self.errors.ensureCursorVisible() |
261 self.errors.ensureCursorVisible() |
261 |
262 |
262 QCoreApplication.processEvents() |
263 QCoreApplication.processEvents() |
263 |
264 |
264 def on_passwordCheckBox_toggled(self, isOn): |
265 def on_passwordCheckBox_toggled(self, isOn): |
265 """ |
266 """ |
266 Private slot to handle the password checkbox toggled. |
267 Private slot to handle the password checkbox toggled. |
267 |
268 |
268 @param isOn flag indicating the status of the check box |
269 @param isOn flag indicating the status of the check box |
269 @type bool |
270 @type bool |
270 """ |
271 """ |
271 if isOn: |
272 if isOn: |
272 self.input.setEchoMode(QLineEdit.EchoMode.Password) |
273 self.input.setEchoMode(QLineEdit.EchoMode.Password) |
273 else: |
274 else: |
274 self.input.setEchoMode(QLineEdit.EchoMode.Normal) |
275 self.input.setEchoMode(QLineEdit.EchoMode.Normal) |
275 |
276 |
276 @pyqtSlot() |
277 @pyqtSlot() |
277 def on_sendButton_clicked(self): |
278 def on_sendButton_clicked(self): |
278 """ |
279 """ |
279 Private slot to send the input to the git process. |
280 Private slot to send the input to the git process. |
280 """ |
281 """ |
281 inputTxt = self.input.text() |
282 inputTxt = self.input.text() |
282 inputTxt += os.linesep |
283 inputTxt += os.linesep |
283 |
284 |
284 if self.passwordCheckBox.isChecked(): |
285 if self.passwordCheckBox.isChecked(): |
285 self.errors.insertPlainText(os.linesep) |
286 self.errors.insertPlainText(os.linesep) |
286 self.errors.ensureCursorVisible() |
287 self.errors.ensureCursorVisible() |
287 else: |
288 else: |
288 self.errors.insertPlainText(inputTxt) |
289 self.errors.insertPlainText(inputTxt) |
289 self.errors.ensureCursorVisible() |
290 self.errors.ensureCursorVisible() |
290 |
291 |
291 self.__process.write(strToQByteArray(inputTxt)) |
292 self.__process.write(strToQByteArray(inputTxt)) |
292 |
293 |
293 self.passwordCheckBox.setChecked(False) |
294 self.passwordCheckBox.setChecked(False) |
294 self.input.clear() |
295 self.input.clear() |
295 |
296 |
296 def on_input_returnPressed(self): |
297 def on_input_returnPressed(self): |
297 """ |
298 """ |
298 Private slot to handle the press of the return key in the input field. |
299 Private slot to handle the press of the return key in the input field. |
299 """ |
300 """ |
300 self.__intercept = True |
301 self.__intercept = True |
301 self.on_sendButton_clicked() |
302 self.on_sendButton_clicked() |
302 |
303 |
303 def keyPressEvent(self, evt): |
304 def keyPressEvent(self, evt): |
304 """ |
305 """ |
305 Protected slot to handle a key press event. |
306 Protected slot to handle a key press event. |
306 |
307 |
307 @param evt the key press event (QKeyEvent) |
308 @param evt the key press event (QKeyEvent) |
308 """ |
309 """ |
309 if self.__intercept: |
310 if self.__intercept: |
310 self.__intercept = False |
311 self.__intercept = False |
311 evt.accept() |
312 evt.accept() |
312 return |
313 return |
313 |
314 |
314 super().keyPressEvent(evt) |
315 super().keyPressEvent(evt) |