eric6/Plugins/VcsPlugins/vcsSubversion/SvnDialog.py

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

eric ide

mercurial