Plugins/VcsPlugins/vcsMercurial/HgDialog.py

changeset 178
dd9f0bca5e2f
child 189
17bb2db7a347
equal deleted inserted replaced
177:c822ccc4d138 178:dd9f0bca5e2f
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog starting a process and showing its output.
8 """
9
10 import os
11
12 from PyQt4.QtCore import QProcess, QTimer, SIGNAL, pyqtSlot
13 from PyQt4.QtGui import QDialog, QDialogButtonBox, QMessageBox, QLineEdit
14
15 from .Ui_HgDialog import Ui_HgDialog
16
17 import Preferences
18
19 class HgDialog(QDialog, Ui_HgDialog):
20 """
21 Class implementing a dialog starting a process and showing its output.
22
23 It starts a QProcess and displays a dialog that
24 shows the output of the process. The dialog is modal,
25 which causes a synchronized execution of the process.
26 """
27 def __init__(self, text, parent = None):
28 """
29 Constructor
30
31 @param text text to be shown by the label (string)
32 @param parent parent widget (QWidget)
33 """
34 QDialog.__init__(self, parent)
35 self.setupUi(self)
36
37 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
38 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
39
40 self.proc = None
41 self.username = ''
42 self.password = ''
43
44 self.outputGroup.setTitle(text)
45
46 def __finish(self):
47 """
48 Private slot called when the process finished or the user pressed the button.
49 """
50 if self.proc is not None and \
51 self.proc.state() != QProcess.NotRunning:
52 self.proc.terminate()
53 QTimer.singleShot(2000, self.proc.kill)
54 self.proc.waitForFinished(3000)
55
56 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
57 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
58 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
59
60 self.inputGroup.setEnabled(False)
61 self.inputGroup.hide()
62
63 self.proc = None
64
65 if Preferences.getVCS("AutoClose") and \
66 self.normal and \
67 self.errors.toPlainText() == "":
68 self.accept()
69
70 if self.__updateCommand and self.normal:
71 # check, if we had additions or deletions
72 lastLine = self.resultbox.toPlainText().splitlines()[-1]
73 if lastLine:
74 adds, merges, deletes, conflicts = \
75 [int(a.split()[0]) for a in lastLine.split(",")]
76 self.__hasAddOrDelete = adds > 0 or deletes > 0
77
78 def on_buttonBox_clicked(self, button):
79 """
80 Private slot called by a button of the button box clicked.
81
82 @param button button that was clicked (QAbstractButton)
83 """
84 if button == self.buttonBox.button(QDialogButtonBox.Close):
85 self.close()
86 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
87 self.__finish()
88
89 def __procFinished(self, exitCode, exitStatus):
90 """
91 Private slot connected to the finished signal.
92
93 @param exitCode exit code of the process (integer)
94 @param exitStatus exit status of the process (QProcess.ExitStatus)
95 """
96 self.normal = (exitStatus == QProcess.NormalExit) and (exitCode == 0)
97 self.__finish()
98
99 def startProcess(self, args, workingDir = None):
100 """
101 Public slot used to start the process.
102
103 @param args list of arguments for the process (list of strings)
104 @param workingDir working directory for the process (string)
105 @return flag indicating a successful start of the process
106 """
107 self.errorGroup.hide()
108 self.normal = False
109 self.intercept = False
110
111 self.__hasAddOrDelete = False
112 self.__updateCommand = args[0] == "update"
113
114 self.proc = QProcess()
115
116 self.resultbox.append(' '.join(args))
117 self.resultbox.append('')
118
119 self.connect(self.proc, SIGNAL('finished(int, QProcess::ExitStatus)'),
120 self.__procFinished)
121 self.connect(self.proc, SIGNAL('readyReadStandardOutput()'),
122 self.__readStdout)
123 self.connect(self.proc, SIGNAL('readyReadStandardError()'),
124 self.__readStderr)
125
126 if workingDir:
127 self.proc.setWorkingDirectory(workingDir)
128 self.proc.start('hg', args)
129 procStarted = self.proc.waitForStarted()
130 if not procStarted:
131 self.buttonBox.setFocus()
132 self.inputGroup.setEnabled(False)
133 QMessageBox.critical(None,
134 self.trUtf8('Process Generation Error'),
135 self.trUtf8(
136 'The process {0} could not be started. '
137 'Ensure, that it is in the search path.'
138 ).format('hg'))
139 else:
140 self.inputGroup.setEnabled(True)
141 self.inputGroup.show()
142 return procStarted
143
144 def normalExit(self):
145 """
146 Public method to check for a normal process termination.
147
148 @return flag indicating normal process termination (boolean)
149 """
150 return self.normal
151
152 def normalExitWithoutErrors(self):
153 """
154 Public method to check for a normal process termination without
155 error messages.
156
157 @return flag indicating normal process termination (boolean)
158 """
159 return self.normal and self.errors.toPlainText() == ""
160
161 def __readStdout(self):
162 """
163 Private slot to handle the readyReadStandardOutput signal.
164
165 It reads the output of the process, formats it and inserts it into
166 the contents pane.
167 """
168 if self.proc is not None:
169 s = str(self.proc.readAllStandardOutput(),
170 Preferences.getSystem("IOEncoding"),
171 'replace')
172 self.resultbox.insertPlainText(s)
173 self.resultbox.ensureCursorVisible()
174
175 def __readStderr(self):
176 """
177 Private slot to handle the readyReadStandardError signal.
178
179 It reads the error output of the process and inserts it into the
180 error pane.
181 """
182 if self.proc is not None:
183 self.errorGroup.show()
184 s = str(self.proc.readAllStandardError(),
185 Preferences.getSystem("IOEncoding"),
186 'replace')
187 self.errors.insertPlainText(s)
188 self.errors.ensureCursorVisible()
189
190 def on_passwordCheckBox_toggled(self, isOn):
191 """
192 Private slot to handle the password checkbox toggled.
193
194 @param isOn flag indicating the status of the check box (boolean)
195 """
196 if isOn:
197 self.input.setEchoMode(QLineEdit.Password)
198 else:
199 self.input.setEchoMode(QLineEdit.Normal)
200
201 @pyqtSlot()
202 def on_sendButton_clicked(self):
203 """
204 Private slot to send the input to the subversion process.
205 """
206 input = self.input.text()
207 input += os.linesep
208
209 if self.passwordCheckBox.isChecked():
210 self.errors.insertPlainText(os.linesep)
211 self.errors.ensureCursorVisible()
212 else:
213 self.errors.insertPlainText(input)
214 self.errors.ensureCursorVisible()
215
216 self.proc.write(input)
217
218 self.passwordCheckBox.setChecked(False)
219 self.input.clear()
220
221 def on_input_returnPressed(self):
222 """
223 Private slot to handle the press of the return key in the input field.
224 """
225 self.intercept = True
226 self.on_sendButton_clicked()
227
228 def keyPressEvent(self, evt):
229 """
230 Protected slot to handle a key press event.
231
232 @param evt the key press event (QKeyEvent)
233 """
234 if self.intercept:
235 self.intercept = False
236 evt.accept()
237 return
238 QDialog.keyPressEvent(self, evt)
239
240 def hasAddOrDelete(self):
241 """
242 Public method to check, if the last action contained an add or delete.
243
244 @return flag indicating the presence of an add or delete (boolean)
245 """
246 return self.__hasAddOrDelete

eric ide

mercurial