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() |