5 |
5 |
6 """ |
6 """ |
7 Module implementing Mercurial shelve browser dialog. |
7 Module implementing Mercurial shelve browser dialog. |
8 """ |
8 """ |
9 |
9 |
10 |
|
11 import os |
10 import os |
12 |
11 |
13 from PyQt5.QtCore import pyqtSlot, Qt, QPoint, QProcess, QTimer |
12 from PyQt5.QtCore import pyqtSlot, Qt, QPoint |
14 from PyQt5.QtGui import QCursor |
13 from PyQt5.QtGui import QCursor |
15 from PyQt5.QtWidgets import ( |
14 from PyQt5.QtWidgets import ( |
16 QWidget, QDialogButtonBox, QTreeWidgetItem, QAbstractButton, QMenu, |
15 QWidget, QDialogButtonBox, QTreeWidgetItem, QAbstractButton, QMenu, |
17 QHeaderView, QApplication, QLineEdit |
16 QHeaderView, QApplication |
18 ) |
17 ) |
19 |
18 |
20 from E5Gui import E5MessageBox |
|
21 |
|
22 from .Ui_HgShelveBrowserDialog import Ui_HgShelveBrowserDialog |
19 from .Ui_HgShelveBrowserDialog import Ui_HgShelveBrowserDialog |
23 |
|
24 from Globals import strToQByteArray |
|
25 |
20 |
26 |
21 |
27 class HgShelveBrowserDialog(QWidget, Ui_HgShelveBrowserDialog): |
22 class HgShelveBrowserDialog(QWidget, Ui_HgShelveBrowserDialog): |
28 """ |
23 """ |
29 Class implementing Mercurial shelve browser dialog. |
24 Class implementing Mercurial shelve browser dialog. |
60 |
55 |
61 self.vcs = vcs |
56 self.vcs = vcs |
62 self.__hgClient = vcs.getClient() |
57 self.__hgClient = vcs.getClient() |
63 self.__resetUI() |
58 self.__resetUI() |
64 |
59 |
65 if self.__hgClient: |
|
66 self.process = None |
|
67 else: |
|
68 self.process = QProcess() |
|
69 self.process.finished.connect(self.__procFinished) |
|
70 self.process.readyReadStandardOutput.connect(self.__readStdout) |
|
71 self.process.readyReadStandardError.connect(self.__readStderr) |
|
72 |
|
73 self.__contextMenu = QMenu() |
60 self.__contextMenu = QMenu() |
74 self.__unshelveAct = self.__contextMenu.addAction( |
61 self.__unshelveAct = self.__contextMenu.addAction( |
75 self.tr("Restore selected shelve"), self.__unshelve) |
62 self.tr("Restore selected shelve"), self.__unshelve) |
76 self.__deleteAct = self.__contextMenu.addAction( |
63 self.__deleteAct = self.__contextMenu.addAction( |
77 self.tr("Delete selected shelves"), self.__deleteShelves) |
64 self.tr("Delete selected shelves"), self.__deleteShelves) |
82 """ |
69 """ |
83 Protected slot implementing a close event handler. |
70 Protected slot implementing a close event handler. |
84 |
71 |
85 @param e close event (QCloseEvent) |
72 @param e close event (QCloseEvent) |
86 """ |
73 """ |
87 if self.__hgClient: |
74 if self.__hgClient.isExecuting(): |
88 if self.__hgClient.isExecuting(): |
75 self.__hgClient.cancel() |
89 self.__hgClient.cancel() |
|
90 else: |
|
91 if ( |
|
92 self.process is not None and |
|
93 self.process.state() != QProcess.NotRunning |
|
94 ): |
|
95 self.process.terminate() |
|
96 QTimer.singleShot(2000, self.process.kill) |
|
97 self.process.waitForFinished(3000) |
|
98 |
76 |
99 self.__position = self.pos() |
77 self.__position = self.pos() |
100 |
78 |
101 e.accept() |
79 e.accept() |
102 |
80 |
160 |
138 |
161 args = self.vcs.initCommand("shelve") |
139 args = self.vcs.initCommand("shelve") |
162 args.append("--list") |
140 args.append("--list") |
163 args.append("--stat") |
141 args.append("--stat") |
164 |
142 |
165 if self.__hgClient: |
143 out, err = self.__hgClient.runcommand(args) |
166 self.inputGroup.setEnabled(False) |
144 self.buf = out.splitlines(True) |
167 self.inputGroup.hide() |
145 if err: |
168 |
146 self.__showError(err) |
169 out, err = self.__hgClient.runcommand(args) |
147 self.__processBuffer() |
170 self.buf = out.splitlines(True) |
148 self.__finish() |
171 if err: |
|
172 self.__showError(err) |
|
173 self.__processBuffer() |
|
174 self.__finish() |
|
175 else: |
|
176 self.process.kill() |
|
177 |
|
178 self.process.setWorkingDirectory(self.repodir) |
|
179 |
|
180 self.inputGroup.setEnabled(True) |
|
181 self.inputGroup.show() |
|
182 |
|
183 self.process.start('hg', args) |
|
184 procStarted = self.process.waitForStarted(5000) |
|
185 if not procStarted: |
|
186 self.inputGroup.setEnabled(False) |
|
187 self.inputGroup.hide() |
|
188 E5MessageBox.critical( |
|
189 self, |
|
190 self.tr('Process Generation Error'), |
|
191 self.tr( |
|
192 'The process {0} could not be started. ' |
|
193 'Ensure, that it is in the search path.' |
|
194 ).format('hg')) |
|
195 |
149 |
196 def start(self, projectDir): |
150 def start(self, projectDir): |
197 """ |
151 """ |
198 Public slot to start the hg shelve command. |
152 Public slot to start the hg shelve command. |
199 |
153 |
216 |
170 |
217 self.shelveList.clear() |
171 self.shelveList.clear() |
218 self.__started = True |
172 self.__started = True |
219 self.__getShelveEntries() |
173 self.__getShelveEntries() |
220 |
174 |
221 def __procFinished(self, exitCode, exitStatus): |
|
222 """ |
|
223 Private slot connected to the finished signal. |
|
224 |
|
225 @param exitCode exit code of the process (integer) |
|
226 @param exitStatus exit status of the process (QProcess.ExitStatus) |
|
227 """ |
|
228 self.__processBuffer() |
|
229 self.__finish() |
|
230 |
|
231 def __finish(self): |
175 def __finish(self): |
232 """ |
176 """ |
233 Private slot called when the process finished or the user pressed |
177 Private slot called when the process finished or the user pressed |
234 the button. |
178 the button. |
235 """ |
179 """ |
236 if ( |
|
237 self.process is not None and |
|
238 self.process.state() != QProcess.NotRunning |
|
239 ): |
|
240 self.process.terminate() |
|
241 QTimer.singleShot(2000, self.process.kill) |
|
242 self.process.waitForFinished(3000) |
|
243 |
|
244 QApplication.restoreOverrideCursor() |
180 QApplication.restoreOverrideCursor() |
245 |
181 |
246 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
182 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True) |
247 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
183 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False) |
248 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
184 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True) |
249 |
185 |
250 self.inputGroup.setEnabled(False) |
|
251 self.inputGroup.hide() |
|
252 self.refreshButton.setEnabled(True) |
186 self.refreshButton.setEnabled(True) |
253 |
187 |
254 def __processBuffer(self): |
188 def __processBuffer(self): |
255 """ |
189 """ |
256 Private method to process the buffered output of the hg shelve command. |
190 Private method to process the buffered output of the hg shelve command. |
301 |
235 |
302 if self.__started: |
236 if self.__started: |
303 self.shelveList.setCurrentItem(self.shelveList.topLevelItem(0)) |
237 self.shelveList.setCurrentItem(self.shelveList.topLevelItem(0)) |
304 self.__started = False |
238 self.__started = False |
305 |
239 |
306 def __readStdout(self): |
|
307 """ |
|
308 Private slot to handle the readyReadStandardOutput signal. |
|
309 |
|
310 It reads the output of the process and inserts it into a buffer. |
|
311 """ |
|
312 self.process.setReadChannel(QProcess.StandardOutput) |
|
313 |
|
314 while self.process.canReadLine(): |
|
315 line = str(self.process.readLine(), self.vcs.getEncoding(), |
|
316 'replace') |
|
317 self.buf.append(line) |
|
318 |
|
319 def __readStderr(self): |
|
320 """ |
|
321 Private slot to handle the readyReadStandardError signal. |
|
322 |
|
323 It reads the error output of the process and inserts it into the |
|
324 error pane. |
|
325 """ |
|
326 if self.process is not None: |
|
327 s = str(self.process.readAllStandardError(), |
|
328 self.vcs.getEncoding(), 'replace') |
|
329 self.__showError(s) |
|
330 |
|
331 def __showError(self, out): |
240 def __showError(self, out): |
332 """ |
241 """ |
333 Private slot to show some error. |
242 Private slot to show some error. |
334 |
243 |
335 @param out error to be shown (string) |
244 @param out error to be shown (string) |
347 """ |
256 """ |
348 if button == self.buttonBox.button(QDialogButtonBox.Close): |
257 if button == self.buttonBox.button(QDialogButtonBox.Close): |
349 self.close() |
258 self.close() |
350 elif button == self.buttonBox.button(QDialogButtonBox.Cancel): |
259 elif button == self.buttonBox.button(QDialogButtonBox.Cancel): |
351 self.cancelled = True |
260 self.cancelled = True |
352 if self.__hgClient: |
261 self.__hgClient.cancel() |
353 self.__hgClient.cancel() |
|
354 else: |
|
355 self.__finish() |
|
356 elif button == self.refreshButton: |
262 elif button == self.refreshButton: |
357 self.on_refreshButton_clicked() |
263 self.on_refreshButton_clicked() |
358 |
264 |
359 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
265 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) |
360 def on_shelveList_currentItemChanged(self, current, previous): |
266 def on_shelveList_currentItemChanged(self, current, previous): |
404 """ |
310 """ |
405 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) |
311 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False) |
406 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True) |
312 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True) |
407 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) |
313 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) |
408 |
314 |
409 self.inputGroup.setEnabled(True) |
|
410 self.inputGroup.show() |
|
411 self.refreshButton.setEnabled(False) |
315 self.refreshButton.setEnabled(False) |
412 |
316 |
413 self.start(self.__projectDir) |
317 self.start(self.__projectDir) |
414 |
|
415 def on_passwordCheckBox_toggled(self, isOn): |
|
416 """ |
|
417 Private slot to handle the password checkbox toggled. |
|
418 |
|
419 @param isOn flag indicating the status of the check box (boolean) |
|
420 """ |
|
421 if isOn: |
|
422 self.input.setEchoMode(QLineEdit.Password) |
|
423 else: |
|
424 self.input.setEchoMode(QLineEdit.Normal) |
|
425 |
|
426 @pyqtSlot() |
|
427 def on_sendButton_clicked(self): |
|
428 """ |
|
429 Private slot to send the input to the mercurial process. |
|
430 """ |
|
431 inputTxt = self.input.text() |
|
432 inputTxt += os.linesep |
|
433 |
|
434 if self.passwordCheckBox.isChecked(): |
|
435 self.errors.insertPlainText(os.linesep) |
|
436 self.errors.ensureCursorVisible() |
|
437 else: |
|
438 self.errors.insertPlainText(inputTxt) |
|
439 self.errors.ensureCursorVisible() |
|
440 self.errorGroup.show() |
|
441 |
|
442 self.process.write(strToQByteArray(inputTxt)) |
|
443 |
|
444 self.passwordCheckBox.setChecked(False) |
|
445 self.input.clear() |
|
446 |
|
447 def on_input_returnPressed(self): |
|
448 """ |
|
449 Private slot to handle the press of the return key in the input field. |
|
450 """ |
|
451 self.intercept = True |
|
452 self.on_sendButton_clicked() |
|
453 |
|
454 def keyPressEvent(self, evt): |
|
455 """ |
|
456 Protected slot to handle a key press event. |
|
457 |
|
458 @param evt the key press event (QKeyEvent) |
|
459 """ |
|
460 if self.intercept: |
|
461 self.intercept = False |
|
462 evt.accept() |
|
463 return |
|
464 super(HgShelveBrowserDialog, self).keyPressEvent(evt) |
|
465 |
318 |
466 def __unshelve(self): |
319 def __unshelve(self): |
467 """ |
320 """ |
468 Private slot to restore the selected shelve of changes. |
321 Private slot to restore the selected shelve of changes. |
469 """ |
322 """ |