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

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
9 9
10 import re 10 import re
11 import os 11 import os
12 12
13 from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QTimer 13 from PyQt6.QtCore import pyqtSlot, Qt, QProcess, QTimer
14 from PyQt6.QtWidgets import ( 14 from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem, QLineEdit
15 QDialog, QDialogButtonBox, QListWidgetItem, QLineEdit
16 )
17 15
18 from EricWidgets import EricMessageBox 16 from EricWidgets import EricMessageBox
19 17
20 from .Ui_SvnChangeListsDialog import Ui_SvnChangeListsDialog 18 from .Ui_SvnChangeListsDialog import Ui_SvnChangeListsDialog
21 19
25 23
26 class SvnChangeListsDialog(QDialog, Ui_SvnChangeListsDialog): 24 class SvnChangeListsDialog(QDialog, Ui_SvnChangeListsDialog):
27 """ 25 """
28 Class implementing a dialog to browse the change lists. 26 Class implementing a dialog to browse the change lists.
29 """ 27 """
28
30 def __init__(self, vcs, parent=None): 29 def __init__(self, vcs, parent=None):
31 """ 30 """
32 Constructor 31 Constructor
33 32
34 @param vcs reference to the vcs object 33 @param vcs reference to the vcs object
35 @param parent parent widget (QWidget) 34 @param parent parent widget (QWidget)
36 """ 35 """
37 super().__init__(parent) 36 super().__init__(parent)
38 self.setupUi(self) 37 self.setupUi(self)
39 self.setWindowFlags(Qt.WindowType.Window) 38 self.setWindowFlags(Qt.WindowType.Window)
40 39
41 self.buttonBox.button( 40 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
42 QDialogButtonBox.StandardButton.Close).setEnabled(False) 41 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
43 self.buttonBox.button( 42
44 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
45
46 self.vcs = vcs 43 self.vcs = vcs
47 44
48 self.process = QProcess() 45 self.process = QProcess()
49 self.process.finished.connect(self.__procFinished) 46 self.process.finished.connect(self.__procFinished)
50 self.process.readyReadStandardOutput.connect(self.__readStdout) 47 self.process.readyReadStandardOutput.connect(self.__readStdout)
51 self.process.readyReadStandardError.connect(self.__readStderr) 48 self.process.readyReadStandardError.connect(self.__readStderr)
52 49
53 self.rx_status = re.compile( 50 self.rx_status = re.compile(
54 '(.{8,9})\\s+([0-9-]+)\\s+([0-9?]+)\\s+(\\S+)\\s+(.+)\\s*') 51 "(.{8,9})\\s+([0-9-]+)\\s+([0-9?]+)\\s+(\\S+)\\s+(.+)\\s*"
52 )
55 # flags (8 or 9 anything), revision, changed rev, author, path 53 # flags (8 or 9 anything), revision, changed rev, author, path
56 self.rx_status2 = re.compile('(.{8,9})\\s+(.+)\\s*') 54 self.rx_status2 = re.compile("(.{8,9})\\s+(.+)\\s*")
57 # flags (8 or 9 anything), path 55 # flags (8 or 9 anything), path
58 self.rx_changelist = re.compile('--- \\S+ .([\\w\\s]+).:\\s+') 56 self.rx_changelist = re.compile("--- \\S+ .([\\w\\s]+).:\\s+")
59 # three dashes, Changelist (translated), quote, 57 # three dashes, Changelist (translated), quote,
60 # changelist name, quote, : 58 # changelist name, quote, :
61 59
62 @pyqtSlot(QListWidgetItem, QListWidgetItem) 60 @pyqtSlot(QListWidgetItem, QListWidgetItem)
63 def on_changeLists_currentItemChanged(self, current, previous): 61 def on_changeLists_currentItemChanged(self, current, previous):
64 """ 62 """
65 Private slot to handle the selection of a new item. 63 Private slot to handle the selection of a new item.
66 64
67 @param current current item (QListWidgetItem) 65 @param current current item (QListWidgetItem)
68 @param previous previous current item (QListWidgetItem) 66 @param previous previous current item (QListWidgetItem)
69 """ 67 """
70 self.filesList.clear() 68 self.filesList.clear()
71 if current is not None: 69 if current is not None:
72 changelist = current.text() 70 changelist = current.text()
73 if changelist in self.changeListsDict: 71 if changelist in self.changeListsDict:
74 self.filesList.addItems( 72 self.filesList.addItems(sorted(self.changeListsDict[changelist]))
75 sorted(self.changeListsDict[changelist])) 73
76
77 def start(self, path): 74 def start(self, path):
78 """ 75 """
79 Public slot to populate the data. 76 Public slot to populate the data.
80 77
81 @param path directory name to show change lists for (string) 78 @param path directory name to show change lists for (string)
82 """ 79 """
83 self.changeListsDict = {} 80 self.changeListsDict = {}
84 81
85 self.filesLabel.setText( 82 self.filesLabel.setText(self.tr("Files (relative to {0}):").format(path))
86 self.tr("Files (relative to {0}):").format(path)) 83
87
88 self.errorGroup.hide() 84 self.errorGroup.hide()
89 self.intercept = False 85 self.intercept = False
90 86
91 self.path = path 87 self.path = path
92 self.currentChangelist = "" 88 self.currentChangelist = ""
93 89
94 args = [] 90 args = []
95 args.append('status') 91 args.append("status")
96 self.vcs.addArguments(args, self.vcs.options['global']) 92 self.vcs.addArguments(args, self.vcs.options["global"])
97 self.vcs.addArguments(args, self.vcs.options['status']) 93 self.vcs.addArguments(args, self.vcs.options["status"])
98 if ( 94 if (
99 '--verbose' not in self.vcs.options['global'] and 95 "--verbose" not in self.vcs.options["global"]
100 '--verbose' not in self.vcs.options['status'] 96 and "--verbose" not in self.vcs.options["status"]
101 ): 97 ):
102 args.append('--verbose') 98 args.append("--verbose")
103 if isinstance(path, list): 99 if isinstance(path, list):
104 self.dname, fnames = self.vcs.splitPathList(path) 100 self.dname, fnames = self.vcs.splitPathList(path)
105 self.vcs.addArguments(args, fnames) 101 self.vcs.addArguments(args, fnames)
106 else: 102 else:
107 self.dname, fname = self.vcs.splitPath(path) 103 self.dname, fname = self.vcs.splitPath(path)
108 args.append(fname) 104 args.append(fname)
109 105
110 self.process.setWorkingDirectory(self.dname) 106 self.process.setWorkingDirectory(self.dname)
111 107
112 self.process.start('svn', args) 108 self.process.start("svn", args)
113 procStarted = self.process.waitForStarted(5000) 109 procStarted = self.process.waitForStarted(5000)
114 if not procStarted: 110 if not procStarted:
115 self.inputGroup.setEnabled(False) 111 self.inputGroup.setEnabled(False)
116 self.inputGroup.hide() 112 self.inputGroup.hide()
117 EricMessageBox.critical( 113 EricMessageBox.critical(
118 self, 114 self,
119 self.tr('Process Generation Error'), 115 self.tr("Process Generation Error"),
120 self.tr( 116 self.tr(
121 'The process {0} could not be started. ' 117 "The process {0} could not be started. "
122 'Ensure, that it is in the search path.' 118 "Ensure, that it is in the search path."
123 ).format('svn')) 119 ).format("svn"),
120 )
124 else: 121 else:
125 self.inputGroup.setEnabled(True) 122 self.inputGroup.setEnabled(True)
126 self.inputGroup.show() 123 self.inputGroup.show()
127 124
128 def __finish(self): 125 def __finish(self):
129 """ 126 """
130 Private slot called when the process finished or the user pressed 127 Private slot called when the process finished or the user pressed
131 the button. 128 the button.
132 """ 129 """
133 if ( 130 if (
134 self.process is not None and 131 self.process is not None
135 self.process.state() != QProcess.ProcessState.NotRunning 132 and self.process.state() != QProcess.ProcessState.NotRunning
136 ): 133 ):
137 self.process.terminate() 134 self.process.terminate()
138 QTimer.singleShot(2000, self.process.kill) 135 QTimer.singleShot(2000, self.process.kill)
139 self.process.waitForFinished(3000) 136 self.process.waitForFinished(3000)
140 137
141 self.buttonBox.button( 138 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
142 QDialogButtonBox.StandardButton.Close).setEnabled(True) 139 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
143 self.buttonBox.button( 140 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
144 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 141
145 self.buttonBox.button(
146 QDialogButtonBox.StandardButton.Close).setDefault(True)
147
148 self.inputGroup.setEnabled(False) 142 self.inputGroup.setEnabled(False)
149 self.inputGroup.hide() 143 self.inputGroup.hide()
150 144
151 if len(self.changeListsDict) == 0: 145 if len(self.changeListsDict) == 0:
152 self.changeLists.addItem(self.tr("No changelists found")) 146 self.changeLists.addItem(self.tr("No changelists found"))
153 self.buttonBox.button( 147 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setFocus(
154 QDialogButtonBox.StandardButton.Close).setFocus( 148 Qt.FocusReason.OtherFocusReason
155 Qt.FocusReason.OtherFocusReason) 149 )
156 else: 150 else:
157 self.changeLists.addItems(sorted(self.changeListsDict.keys())) 151 self.changeLists.addItems(sorted(self.changeListsDict.keys()))
158 self.changeLists.setCurrentRow(0) 152 self.changeLists.setCurrentRow(0)
159 self.changeLists.setFocus(Qt.FocusReason.OtherFocusReason) 153 self.changeLists.setFocus(Qt.FocusReason.OtherFocusReason)
160 154
161 def on_buttonBox_clicked(self, button): 155 def on_buttonBox_clicked(self, button):
162 """ 156 """
163 Private slot called by a button of the button box clicked. 157 Private slot called by a button of the button box clicked.
164 158
165 @param button button that was clicked (QAbstractButton) 159 @param button button that was clicked (QAbstractButton)
166 """ 160 """
167 if button == self.buttonBox.button( 161 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
168 QDialogButtonBox.StandardButton.Close
169 ):
170 self.close() 162 self.close()
171 elif button == self.buttonBox.button( 163 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
172 QDialogButtonBox.StandardButton.Cancel
173 ):
174 self.__finish() 164 self.__finish()
175 165
176 def __procFinished(self, exitCode, exitStatus): 166 def __procFinished(self, exitCode, exitStatus):
177 """ 167 """
178 Private slot connected to the finished signal. 168 Private slot connected to the finished signal.
179 169
180 @param exitCode exit code of the process (integer) 170 @param exitCode exit code of the process (integer)
181 @param exitStatus exit status of the process (QProcess.ExitStatus) 171 @param exitStatus exit status of the process (QProcess.ExitStatus)
182 """ 172 """
183 self.__finish() 173 self.__finish()
184 174
185 def __readStdout(self): 175 def __readStdout(self):
186 """ 176 """
187 Private slot to handle the readyReadStandardOutput signal. 177 Private slot to handle the readyReadStandardOutput signal.
188 178
189 It reads the output of the process, formats it and inserts it into 179 It reads the output of the process, formats it and inserts it into
190 the contents pane. 180 the contents pane.
191 """ 181 """
192 if self.process is not None: 182 if self.process is not None:
193 self.process.setReadChannel(QProcess.ProcessChannel.StandardOutput) 183 self.process.setReadChannel(QProcess.ProcessChannel.StandardOutput)
194 184
195 while self.process.canReadLine(): 185 while self.process.canReadLine():
196 s = str(self.process.readLine(), 186 s = str(
197 Preferences.getSystem("IOEncoding"), 187 self.process.readLine(),
198 'replace') 188 Preferences.getSystem("IOEncoding"),
199 match = ( 189 "replace",
200 self.rx_status.fullmatch(s) or
201 self.rx_status2.fullmatch(s)
202 ) 190 )
191 match = self.rx_status.fullmatch(s) or self.rx_status2.fullmatch(s)
203 if self.currentChangelist != "" and match is not None: 192 if self.currentChangelist != "" and match is not None:
204 if match.re is self.rx_status: 193 if match.re is self.rx_status:
205 file = match.group(5).strip() 194 file = match.group(5).strip()
206 filename = file.replace(self.path + os.sep, "") 195 filename = file.replace(self.path + os.sep, "")
207 if filename not in self.changeListsDict[ 196 if filename not in self.changeListsDict[self.currentChangelist]:
208 self.currentChangelist 197 self.changeListsDict[self.currentChangelist].append(
209 ]: 198 filename
210 self.changeListsDict[ 199 )
211 self.currentChangelist].append(filename)
212 else: 200 else:
213 file = match.group(2).strip() 201 file = match.group(2).strip()
214 filename = file.replace(self.path + os.sep, "") 202 filename = file.replace(self.path + os.sep, "")
215 if filename not in self.changeListsDict[ 203 if filename not in self.changeListsDict[self.currentChangelist]:
216 self.currentChangelist 204 self.changeListsDict[self.currentChangelist].append(
217 ]: 205 filename
218 self.changeListsDict[ 206 )
219 self.currentChangelist].append(filename)
220 else: 207 else:
221 match = self.rx_changelist.fullmatch(s) 208 match = self.rx_changelist.fullmatch(s)
222 if match is not None: 209 if match is not None:
223 self.currentChangelist = match.group(1) 210 self.currentChangelist = match.group(1)
224 if self.currentChangelist not in self.changeListsDict: 211 if self.currentChangelist not in self.changeListsDict:
225 self.changeListsDict[self.currentChangelist] = [] 212 self.changeListsDict[self.currentChangelist] = []
226 213
227 def __readStderr(self): 214 def __readStderr(self):
228 """ 215 """
229 Private slot to handle the readyReadStandardError signal. 216 Private slot to handle the readyReadStandardError signal.
230 217
231 It reads the error output of the process and inserts it into the 218 It reads the error output of the process and inserts it into the
232 error pane. 219 error pane.
233 """ 220 """
234 if self.process is not None: 221 if self.process is not None:
235 self.errorGroup.show() 222 self.errorGroup.show()
236 s = str(self.process.readAllStandardError(), 223 s = str(
237 Preferences.getSystem("IOEncoding"), 224 self.process.readAllStandardError(),
238 'replace') 225 Preferences.getSystem("IOEncoding"),
226 "replace",
227 )
239 self.errors.insertPlainText(s) 228 self.errors.insertPlainText(s)
240 self.errors.ensureCursorVisible() 229 self.errors.ensureCursorVisible()
241 230
242 def on_passwordCheckBox_toggled(self, isOn): 231 def on_passwordCheckBox_toggled(self, isOn):
243 """ 232 """
244 Private slot to handle the password checkbox toggled. 233 Private slot to handle the password checkbox toggled.
245 234
246 @param isOn flag indicating the status of the check box (boolean) 235 @param isOn flag indicating the status of the check box (boolean)
247 """ 236 """
248 if isOn: 237 if isOn:
249 self.input.setEchoMode(QLineEdit.EchoMode.Password) 238 self.input.setEchoMode(QLineEdit.EchoMode.Password)
250 else: 239 else:
251 self.input.setEchoMode(QLineEdit.EchoMode.Normal) 240 self.input.setEchoMode(QLineEdit.EchoMode.Normal)
252 241
253 @pyqtSlot() 242 @pyqtSlot()
254 def on_sendButton_clicked(self): 243 def on_sendButton_clicked(self):
255 """ 244 """
256 Private slot to send the input to the subversion process. 245 Private slot to send the input to the subversion process.
257 """ 246 """
258 inputTxt = self.input.text() 247 inputTxt = self.input.text()
259 inputTxt += os.linesep 248 inputTxt += os.linesep
260 249
261 if self.passwordCheckBox.isChecked(): 250 if self.passwordCheckBox.isChecked():
262 self.errors.insertPlainText(os.linesep) 251 self.errors.insertPlainText(os.linesep)
263 self.errors.ensureCursorVisible() 252 self.errors.ensureCursorVisible()
264 else: 253 else:
265 self.errors.insertPlainText(inputTxt) 254 self.errors.insertPlainText(inputTxt)
266 self.errors.ensureCursorVisible() 255 self.errors.ensureCursorVisible()
267 256
268 self.process.write(strToQByteArray(inputTxt)) 257 self.process.write(strToQByteArray(inputTxt))
269 258
270 self.passwordCheckBox.setChecked(False) 259 self.passwordCheckBox.setChecked(False)
271 self.input.clear() 260 self.input.clear()
272 261
273 def on_input_returnPressed(self): 262 def on_input_returnPressed(self):
274 """ 263 """
275 Private slot to handle the press of the return key in the input field. 264 Private slot to handle the press of the return key in the input field.
276 """ 265 """
277 self.intercept = True 266 self.intercept = True
278 self.on_sendButton_clicked() 267 self.on_sendButton_clicked()
279 268
280 def keyPressEvent(self, evt): 269 def keyPressEvent(self, evt):
281 """ 270 """
282 Protected slot to handle a key press event. 271 Protected slot to handle a key press event.
283 272
284 @param evt the key press event (QKeyEvent) 273 @param evt the key press event (QKeyEvent)
285 """ 274 """
286 if self.intercept: 275 if self.intercept:
287 self.intercept = False 276 self.intercept = False
288 evt.accept() 277 evt.accept()

eric ide

mercurial