8 """ |
8 """ |
9 |
9 |
10 |
10 |
11 import os |
11 import os |
12 |
12 |
13 from PyQt5.QtCore import pyqtSlot, QProcess, Qt, QTimer, QCoreApplication |
13 from PyQt5.QtCore import Qt, QCoreApplication |
14 from PyQt5.QtWidgets import ( |
14 from PyQt5.QtWidgets import ( |
15 QDialog, QDialogButtonBox, QHeaderView, QTreeWidgetItem, QLineEdit |
15 QDialog, QDialogButtonBox, QHeaderView, QTreeWidgetItem |
16 ) |
16 ) |
17 |
17 |
18 from E5Gui import E5MessageBox |
|
19 |
|
20 from .Ui_HgQueuesListDialog import Ui_HgQueuesListDialog |
18 from .Ui_HgQueuesListDialog import Ui_HgQueuesListDialog |
21 |
|
22 from Globals import strToQByteArray |
|
23 |
19 |
24 |
20 |
25 class HgQueuesListDialog(QDialog, Ui_HgQueuesListDialog): |
21 class HgQueuesListDialog(QDialog, Ui_HgQueuesListDialog): |
26 """ |
22 """ |
27 Class implementing a dialog to show a list of applied and unapplied |
23 Class implementing a dialog to show a list of applied and unapplied |
44 self.vcs = vcs |
40 self.vcs = vcs |
45 self.__hgClient = vcs.getClient() |
41 self.__hgClient = vcs.getClient() |
46 |
42 |
47 self.patchesList.header().setSortIndicator(0, Qt.AscendingOrder) |
43 self.patchesList.header().setSortIndicator(0, Qt.AscendingOrder) |
48 |
44 |
49 if self.__hgClient: |
|
50 self.process = None |
|
51 else: |
|
52 self.process = QProcess() |
|
53 self.process.finished.connect(self.__procFinished) |
|
54 self.process.readyReadStandardOutput.connect(self.__readStdout) |
|
55 self.process.readyReadStandardError.connect(self.__readStderr) |
|
56 |
|
57 self.__statusDict = { |
45 self.__statusDict = { |
58 "A": self.tr("applied"), |
46 "A": self.tr("applied"), |
59 "U": self.tr("not applied"), |
47 "U": self.tr("not applied"), |
60 "G": self.tr("guarded"), |
48 "G": self.tr("guarded"), |
61 "D": self.tr("missing"), |
49 "D": self.tr("missing"), |
124 args.append('--summary') |
103 args.append('--summary') |
125 args.append('--verbose') |
104 args.append('--verbose') |
126 if missing: |
105 if missing: |
127 args.append('--missing') |
106 args.append('--missing') |
128 |
107 |
129 if self.__hgClient: |
108 out, err = self.__hgClient.runcommand(args) |
130 self.inputGroup.setEnabled(False) |
109 if err: |
131 self.inputGroup.hide() |
110 self.__showError(err) |
132 |
111 if out: |
133 out, err = self.__hgClient.runcommand(args) |
112 for line in out.splitlines(): |
134 if err: |
113 self.__processOutputLine(line) |
135 self.__showError(err) |
114 if self.__hgClient.wasCanceled(): |
136 if out: |
115 self.__mode = "" |
137 for line in out.splitlines(): |
116 break |
138 self.__processOutputLine(line) |
117 if self.__mode == "qseries": |
139 if self.__hgClient.wasCanceled(): |
118 self.__getSeries(True) |
140 self.__mode = "" |
119 elif self.__mode == "missing": |
141 break |
120 self.__getTop() |
142 if self.__mode == "qseries": |
121 else: |
143 self.__getSeries(True) |
122 self.__finish() |
144 elif self.__mode == "missing": |
|
145 self.__getTop() |
|
146 else: |
|
147 self.__finish() |
|
148 else: |
|
149 self.process.kill() |
|
150 self.process.setWorkingDirectory(self.__repodir) |
|
151 |
|
152 self.process.start('hg', args) |
|
153 procStarted = self.process.waitForStarted(5000) |
|
154 if not procStarted: |
|
155 self.inputGroup.setEnabled(False) |
|
156 self.inputGroup.hide() |
|
157 E5MessageBox.critical( |
|
158 self, |
|
159 self.tr('Process Generation Error'), |
|
160 self.tr( |
|
161 'The process {0} could not be started. ' |
|
162 'Ensure, that it is in the search path.' |
|
163 ).format('hg')) |
|
164 else: |
|
165 self.inputGroup.setEnabled(True) |
|
166 self.inputGroup.show() |
|
167 |
123 |
168 def __getTop(self): |
124 def __getTop(self): |
169 """ |
125 """ |
170 Private slot to get patch at the top of the stack. |
126 Private slot to get patch at the top of the stack. |
171 """ |
127 """ |
172 self.__mode = "qtop" |
128 self.__mode = "qtop" |
173 |
129 |
174 args = self.vcs.initCommand("qtop") |
130 args = self.vcs.initCommand("qtop") |
175 |
131 |
176 if self.__hgClient: |
132 out, err = self.__hgClient.runcommand(args) |
177 self.inputGroup.setEnabled(False) |
133 if err: |
178 self.inputGroup.hide() |
134 self.__showError(err) |
179 |
135 if out: |
180 out, err = self.__hgClient.runcommand(args) |
136 for line in out.splitlines(): |
181 if err: |
137 self.__processOutputLine(line) |
182 self.__showError(err) |
138 if self.__hgClient.wasCanceled(): |
183 if out: |
139 break |
184 for line in out.splitlines(): |
140 self.__finish() |
185 self.__processOutputLine(line) |
|
186 if self.__hgClient.wasCanceled(): |
|
187 break |
|
188 self.__finish() |
|
189 else: |
|
190 self.process.kill() |
|
191 self.process.setWorkingDirectory(self.__repodir) |
|
192 |
|
193 self.process.start('hg', args) |
|
194 procStarted = self.process.waitForStarted(5000) |
|
195 if not procStarted: |
|
196 self.inputGroup.setEnabled(False) |
|
197 self.inputGroup.hide() |
|
198 E5MessageBox.critical( |
|
199 self, |
|
200 self.tr('Process Generation Error'), |
|
201 self.tr( |
|
202 'The process {0} could not be started. ' |
|
203 'Ensure, that it is in the search path.' |
|
204 ).format('hg')) |
|
205 else: |
|
206 self.inputGroup.setEnabled(True) |
|
207 self.inputGroup.show() |
|
208 |
141 |
209 def __finish(self): |
142 def __finish(self): |
210 """ |
143 """ |
211 Private slot called when the process finished or the user pressed |
144 Private slot called when the process finished or the user pressed |
212 the button. |
145 the button. |
213 """ |
146 """ |
214 if ( |
|
215 self.process is not None and |
|
216 self.process.state() != QProcess.NotRunning |
|
217 ): |
|
218 self.process.terminate() |
|
219 QTimer.singleShot(2000, self.process.kill) |
|
220 self.process.waitForFinished(3000) |
|
221 |
|
222 self.inputGroup.setEnabled(False) |
|
223 self.inputGroup.hide() |
|
224 |
|
225 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
147 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
226 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
148 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
227 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
149 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
228 self.buttonBox.button(QDialogButtonBox.Close).setFocus( |
150 self.buttonBox.button(QDialogButtonBox.Close).setFocus( |
229 Qt.OtherFocusReason) |
151 Qt.OtherFocusReason) |
332 for column in range(itm.columnCount()): |
237 for column in range(itm.columnCount()): |
333 font = itm.font(column) |
238 font = itm.font(column) |
334 font.setBold(True) |
239 font.setBold(True) |
335 itm.setFont(column, font) |
240 itm.setFont(column, font) |
336 |
241 |
337 def __readStdout(self): |
|
338 """ |
|
339 Private slot to handle the readyReadStdout signal. |
|
340 |
|
341 It reads the output of the process, formats it and inserts it into |
|
342 the contents pane. |
|
343 """ |
|
344 self.process.setReadChannel(QProcess.StandardOutput) |
|
345 |
|
346 while self.process.canReadLine(): |
|
347 s = str(self.process.readLine(), self.vcs.getEncoding(), |
|
348 'replace').strip() |
|
349 self.__processOutputLine(s) |
|
350 |
|
351 def __processOutputLine(self, line): |
242 def __processOutputLine(self, line): |
352 """ |
243 """ |
353 Private method to process the lines of output. |
244 Private method to process the lines of output. |
354 |
245 |
355 @param line output line to be processed (string) |
246 @param line output line to be processed (string) |
370 index, status, name = li[:3] |
261 index, status, name = li[:3] |
371 else: |
262 else: |
372 return |
263 return |
373 self.__generateItem(index, status, name, summary) |
264 self.__generateItem(index, status, name, summary) |
374 |
265 |
375 def __readStderr(self): |
|
376 """ |
|
377 Private slot to handle the readyReadStderr signal. |
|
378 |
|
379 It reads the error output of the process and inserts it into the |
|
380 error pane. |
|
381 """ |
|
382 if self.process is not None: |
|
383 s = str(self.process.readAllStandardError(), |
|
384 self.vcs.getEncoding(), 'replace') |
|
385 self.__showError(s) |
|
386 |
|
387 def __showError(self, out): |
266 def __showError(self, out): |
388 """ |
267 """ |
389 Private slot to show some error. |
268 Private slot to show some error. |
390 |
269 |
391 @param out error to be shown (string) |
270 @param out error to be shown (string) |
392 """ |
271 """ |
393 self.errorGroup.show() |
272 self.errorGroup.show() |
394 self.errors.insertPlainText(out) |
273 self.errors.insertPlainText(out) |
395 self.errors.ensureCursorVisible() |
274 self.errors.ensureCursorVisible() |
396 |
|
397 def on_passwordCheckBox_toggled(self, isOn): |
|
398 """ |
|
399 Private slot to handle the password checkbox toggled. |
|
400 |
|
401 @param isOn flag indicating the status of the check box (boolean) |
|
402 """ |
|
403 if isOn: |
|
404 self.input.setEchoMode(QLineEdit.Password) |
|
405 else: |
|
406 self.input.setEchoMode(QLineEdit.Normal) |
|
407 |
|
408 @pyqtSlot() |
|
409 def on_sendButton_clicked(self): |
|
410 """ |
|
411 Private slot to send the input to the subversion process. |
|
412 """ |
|
413 inputTxt = self.input.text() |
|
414 inputTxt += os.linesep |
|
415 |
|
416 if self.passwordCheckBox.isChecked(): |
|
417 self.errors.insertPlainText(os.linesep) |
|
418 self.errors.ensureCursorVisible() |
|
419 else: |
|
420 self.errors.insertPlainText(inputTxt) |
|
421 self.errors.ensureCursorVisible() |
|
422 |
|
423 self.process.write(strToQByteArray(inputTxt)) |
|
424 |
|
425 self.passwordCheckBox.setChecked(False) |
|
426 self.input.clear() |
|
427 |
|
428 def on_input_returnPressed(self): |
|
429 """ |
|
430 Private slot to handle the press of the return key in the input field. |
|
431 """ |
|
432 self.intercept = True |
|
433 self.on_sendButton_clicked() |
|
434 |
|
435 def keyPressEvent(self, evt): |
|
436 """ |
|
437 Protected slot to handle a key press event. |
|
438 |
|
439 @param evt the key press event (QKeyEvent) |
|
440 """ |
|
441 if self.intercept: |
|
442 self.intercept = False |
|
443 evt.accept() |
|
444 return |
|
445 super(HgQueuesListDialog, self).keyPressEvent(evt) |
|