src/eric7/Plugins/VcsPlugins/vcsSubversion/SvnBlameDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 import os 10 import os
11 11
12 from PyQt6.QtCore import QTimer, QProcess, Qt, pyqtSlot 12 from PyQt6.QtCore import QTimer, QProcess, Qt, pyqtSlot
13 from PyQt6.QtWidgets import ( 13 from PyQt6.QtWidgets import (
14 QHeaderView, QLineEdit, QDialog, QDialogButtonBox, QTreeWidgetItem 14 QHeaderView,
15 QLineEdit,
16 QDialog,
17 QDialogButtonBox,
18 QTreeWidgetItem,
15 ) 19 )
16 20
17 from EricWidgets import EricMessageBox 21 from EricWidgets import EricMessageBox
18 22
19 from .Ui_SvnBlameDialog import Ui_SvnBlameDialog 23 from .Ui_SvnBlameDialog import Ui_SvnBlameDialog
24 28
25 class SvnBlameDialog(QDialog, Ui_SvnBlameDialog): 29 class SvnBlameDialog(QDialog, Ui_SvnBlameDialog):
26 """ 30 """
27 Class implementing a dialog to show the output of the svn blame command. 31 Class implementing a dialog to show the output of the svn blame command.
28 """ 32 """
33
29 def __init__(self, vcs, parent=None): 34 def __init__(self, vcs, parent=None):
30 """ 35 """
31 Constructor 36 Constructor
32 37
33 @param vcs reference to the vcs object 38 @param vcs reference to the vcs object
34 @param parent parent widget (QWidget) 39 @param parent parent widget (QWidget)
35 """ 40 """
36 super().__init__(parent) 41 super().__init__(parent)
37 self.setupUi(self) 42 self.setupUi(self)
38 self.setWindowFlags(Qt.WindowType.Window) 43 self.setWindowFlags(Qt.WindowType.Window)
39 44
40 self.buttonBox.button( 45 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
41 QDialogButtonBox.StandardButton.Close).setEnabled(False) 46 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
42 self.buttonBox.button( 47
43 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
44
45 self.vcs = vcs 48 self.vcs = vcs
46 49
47 self.blameList.headerItem().setText(self.blameList.columnCount(), "") 50 self.blameList.headerItem().setText(self.blameList.columnCount(), "")
48 font = Preferences.getEditorOtherFonts("MonospacedFont") 51 font = Preferences.getEditorOtherFonts("MonospacedFont")
49 self.blameList.setFont(font) 52 self.blameList.setFont(font)
50 53
51 self.__ioEncoding = Preferences.getSystem("IOEncoding") 54 self.__ioEncoding = Preferences.getSystem("IOEncoding")
52 55
53 self.process = QProcess() 56 self.process = QProcess()
54 self.process.finished.connect(self.__procFinished) 57 self.process.finished.connect(self.__procFinished)
55 self.process.readyReadStandardOutput.connect(self.__readStdout) 58 self.process.readyReadStandardOutput.connect(self.__readStdout)
56 self.process.readyReadStandardError.connect(self.__readStderr) 59 self.process.readyReadStandardError.connect(self.__readStderr)
57 60
58 def closeEvent(self, e): 61 def closeEvent(self, e):
59 """ 62 """
60 Protected slot implementing a close event handler. 63 Protected slot implementing a close event handler.
61 64
62 @param e close event (QCloseEvent) 65 @param e close event (QCloseEvent)
63 """ 66 """
64 if ( 67 if (
65 self.process is not None and 68 self.process is not None
66 self.process.state() != QProcess.ProcessState.NotRunning 69 and self.process.state() != QProcess.ProcessState.NotRunning
67 ): 70 ):
68 self.process.terminate() 71 self.process.terminate()
69 QTimer.singleShot(2000, self.process.kill) 72 QTimer.singleShot(2000, self.process.kill)
70 self.process.waitForFinished(3000) 73 self.process.waitForFinished(3000)
71 74
72 e.accept() 75 e.accept()
73 76
74 def start(self, fn): 77 def start(self, fn):
75 """ 78 """
76 Public slot to start the svn blame command. 79 Public slot to start the svn blame command.
77 80
78 @param fn filename to show the blame for (string) 81 @param fn filename to show the blame for (string)
79 """ 82 """
80 self.blameList.clear() 83 self.blameList.clear()
81 self.errorGroup.hide() 84 self.errorGroup.hide()
82 self.intercept = False 85 self.intercept = False
83 self.activateWindow() 86 self.activateWindow()
84 self.lineno = 1 87 self.lineno = 1
85 88
86 dname, fname = self.vcs.splitPath(fn) 89 dname, fname = self.vcs.splitPath(fn)
87 90
88 self.process.kill() 91 self.process.kill()
89 92
90 args = [] 93 args = []
91 args.append('blame') 94 args.append("blame")
92 self.vcs.addArguments(args, self.vcs.options['global']) 95 self.vcs.addArguments(args, self.vcs.options["global"])
93 args.append(fname) 96 args.append(fname)
94 97
95 self.process.setWorkingDirectory(dname) 98 self.process.setWorkingDirectory(dname)
96 99
97 self.process.start('svn', args) 100 self.process.start("svn", args)
98 procStarted = self.process.waitForStarted(5000) 101 procStarted = self.process.waitForStarted(5000)
99 if not procStarted: 102 if not procStarted:
100 self.inputGroup.setEnabled(False) 103 self.inputGroup.setEnabled(False)
101 self.inputGroup.hide() 104 self.inputGroup.hide()
102 EricMessageBox.critical( 105 EricMessageBox.critical(
103 self, 106 self,
104 self.tr('Process Generation Error'), 107 self.tr("Process Generation Error"),
105 self.tr( 108 self.tr(
106 'The process {0} could not be started. ' 109 "The process {0} could not be started. "
107 'Ensure, that it is in the search path.' 110 "Ensure, that it is in the search path."
108 ).format('svn')) 111 ).format("svn"),
112 )
109 else: 113 else:
110 self.inputGroup.setEnabled(True) 114 self.inputGroup.setEnabled(True)
111 self.inputGroup.show() 115 self.inputGroup.show()
112 116
113 def __finish(self): 117 def __finish(self):
114 """ 118 """
115 Private slot called when the process finished or the user pressed the 119 Private slot called when the process finished or the user pressed the
116 button. 120 button.
117 """ 121 """
118 if ( 122 if (
119 self.process is not None and 123 self.process is not None
120 self.process.state() != QProcess.ProcessState.NotRunning 124 and self.process.state() != QProcess.ProcessState.NotRunning
121 ): 125 ):
122 self.process.terminate() 126 self.process.terminate()
123 QTimer.singleShot(2000, self.process.kill) 127 QTimer.singleShot(2000, self.process.kill)
124 self.process.waitForFinished(3000) 128 self.process.waitForFinished(3000)
125 129
126 self.buttonBox.button( 130 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
127 QDialogButtonBox.StandardButton.Close).setEnabled(True) 131 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
128 self.buttonBox.button( 132 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
129 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 133 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus(
130 self.buttonBox.button( 134 Qt.FocusReason.OtherFocusReason
131 QDialogButtonBox.StandardButton.Close).setDefault(True) 135 )
132 self.buttonBox.button( 136
133 QDialogButtonBox.StandardButton.Close).setFocus(
134 Qt.FocusReason.OtherFocusReason)
135
136 self.inputGroup.setEnabled(False) 137 self.inputGroup.setEnabled(False)
137 self.inputGroup.hide() 138 self.inputGroup.hide()
138 139
139 self.__resizeColumns() 140 self.__resizeColumns()
140 141
141 def on_buttonBox_clicked(self, button): 142 def on_buttonBox_clicked(self, button):
142 """ 143 """
143 Private slot called by a button of the button box clicked. 144 Private slot called by a button of the button box clicked.
144 145
145 @param button button that was clicked (QAbstractButton) 146 @param button button that was clicked (QAbstractButton)
146 """ 147 """
147 if button == self.buttonBox.button( 148 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
148 QDialogButtonBox.StandardButton.Close
149 ):
150 self.close() 149 self.close()
151 elif button == self.buttonBox.button( 150 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
152 QDialogButtonBox.StandardButton.Cancel
153 ):
154 self.__finish() 151 self.__finish()
155 152
156 def __procFinished(self, exitCode, exitStatus): 153 def __procFinished(self, exitCode, exitStatus):
157 """ 154 """
158 Private slot connected to the finished signal. 155 Private slot connected to the finished signal.
159 156
160 @param exitCode exit code of the process (integer) 157 @param exitCode exit code of the process (integer)
161 @param exitStatus exit status of the process (QProcess.ExitStatus) 158 @param exitStatus exit status of the process (QProcess.ExitStatus)
162 """ 159 """
163 self.__finish() 160 self.__finish()
164 161
165 def __resizeColumns(self): 162 def __resizeColumns(self):
166 """ 163 """
167 Private method to resize the list columns. 164 Private method to resize the list columns.
168 """ 165 """
169 self.blameList.header().resizeSections( 166 self.blameList.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
170 QHeaderView.ResizeMode.ResizeToContents) 167
171
172 def __generateItem(self, revision, author, text): 168 def __generateItem(self, revision, author, text):
173 """ 169 """
174 Private method to generate a blame item in the blame list. 170 Private method to generate a blame item in the blame list.
175 171
176 @param revision revision string (string) 172 @param revision revision string (string)
177 @param author author of the change (string) 173 @param author author of the change (string)
178 @param text line of text from the annotated file (string) 174 @param text line of text from the annotated file (string)
179 """ 175 """
180 itm = QTreeWidgetItem( 176 itm = QTreeWidgetItem(
181 self.blameList, 177 self.blameList, [revision, author, "{0:d}".format(self.lineno), text]
182 [revision, author, "{0:d}".format(self.lineno), text]) 178 )
183 self.lineno += 1 179 self.lineno += 1
184 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignRight) 180 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignRight)
185 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignRight) 181 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignRight)
186 182
187 def __readStdout(self): 183 def __readStdout(self):
188 """ 184 """
189 Private slot to handle the readyReadStdout signal. 185 Private slot to handle the readyReadStdout signal.
190 186
191 It reads the output of the process, formats it and inserts it into 187 It reads the output of the process, formats it and inserts it into
192 the contents pane. 188 the contents pane.
193 """ 189 """
194 self.process.setReadChannel(QProcess.ProcessChannel.StandardOutput) 190 self.process.setReadChannel(QProcess.ProcessChannel.StandardOutput)
195 191
196 while self.process.canReadLine(): 192 while self.process.canReadLine():
197 s = str( 193 s = str(self.process.readLine(), self.__ioEncoding, "replace").strip()
198 self.process.readLine(), self.__ioEncoding, 'replace').strip()
199 rev, s = s.split(None, 1) 194 rev, s = s.split(None, 1)
200 try: 195 try:
201 author, text = s.split(' ', 1) 196 author, text = s.split(" ", 1)
202 except ValueError: 197 except ValueError:
203 author = s.strip() 198 author = s.strip()
204 text = "" 199 text = ""
205 self.__generateItem(rev, author, text) 200 self.__generateItem(rev, author, text)
206 201
207 def __readStderr(self): 202 def __readStderr(self):
208 """ 203 """
209 Private slot to handle the readyReadStderr signal. 204 Private slot to handle the readyReadStderr signal.
210 205
211 It reads the error output of the process and inserts it into the 206 It reads the error output of the process and inserts it into the
212 error pane. 207 error pane.
213 """ 208 """
214 if self.process is not None: 209 if self.process is not None:
215 self.errorGroup.show() 210 self.errorGroup.show()
216 s = str(self.process.readAllStandardError(), 211 s = str(
217 Preferences.getSystem("IOEncoding"), 212 self.process.readAllStandardError(),
218 'replace') 213 Preferences.getSystem("IOEncoding"),
214 "replace",
215 )
219 self.errors.insertPlainText(s) 216 self.errors.insertPlainText(s)
220 self.errors.ensureCursorVisible() 217 self.errors.ensureCursorVisible()
221 218
222 def on_passwordCheckBox_toggled(self, isOn): 219 def on_passwordCheckBox_toggled(self, isOn):
223 """ 220 """
224 Private slot to handle the password checkbox toggled. 221 Private slot to handle the password checkbox toggled.
225 222
226 @param isOn flag indicating the status of the check box (boolean) 223 @param isOn flag indicating the status of the check box (boolean)
227 """ 224 """
228 if isOn: 225 if isOn:
229 self.input.setEchoMode(QLineEdit.EchoMode.Password) 226 self.input.setEchoMode(QLineEdit.EchoMode.Password)
230 else: 227 else:
231 self.input.setEchoMode(QLineEdit.EchoMode.Normal) 228 self.input.setEchoMode(QLineEdit.EchoMode.Normal)
232 229
233 @pyqtSlot() 230 @pyqtSlot()
234 def on_sendButton_clicked(self): 231 def on_sendButton_clicked(self):
235 """ 232 """
236 Private slot to send the input to the subversion process. 233 Private slot to send the input to the subversion process.
237 """ 234 """
238 inputTxt = self.input.text() 235 inputTxt = self.input.text()
239 inputTxt += os.linesep 236 inputTxt += os.linesep
240 237
241 if self.passwordCheckBox.isChecked(): 238 if self.passwordCheckBox.isChecked():
242 self.errors.insertPlainText(os.linesep) 239 self.errors.insertPlainText(os.linesep)
243 self.errors.ensureCursorVisible() 240 self.errors.ensureCursorVisible()
244 else: 241 else:
245 self.errors.insertPlainText(inputTxt) 242 self.errors.insertPlainText(inputTxt)
246 self.errors.ensureCursorVisible() 243 self.errors.ensureCursorVisible()
247 244
248 self.process.write(strToQByteArray(inputTxt)) 245 self.process.write(strToQByteArray(inputTxt))
249 246
250 self.passwordCheckBox.setChecked(False) 247 self.passwordCheckBox.setChecked(False)
251 self.input.clear() 248 self.input.clear()
252 249
253 def on_input_returnPressed(self): 250 def on_input_returnPressed(self):
254 """ 251 """
255 Private slot to handle the press of the return key in the input field. 252 Private slot to handle the press of the return key in the input field.
256 """ 253 """
257 self.intercept = True 254 self.intercept = True
258 self.on_sendButton_clicked() 255 self.on_sendButton_clicked()
259 256
260 def keyPressEvent(self, evt): 257 def keyPressEvent(self, evt):
261 """ 258 """
262 Protected slot to handle a key press event. 259 Protected slot to handle a key press event.
263 260
264 @param evt the key press event (QKeyEvent) 261 @param evt the key press event (QKeyEvent)
265 """ 262 """
266 if self.intercept: 263 if self.intercept:
267 self.intercept = False 264 self.intercept = False
268 evt.accept() 265 evt.accept()

eric ide

mercurial