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 |