28 |
32 |
29 class SvnRepoBrowserDialog(QDialog, Ui_SvnRepoBrowserDialog): |
33 class SvnRepoBrowserDialog(QDialog, Ui_SvnRepoBrowserDialog): |
30 """ |
34 """ |
31 Class implementing the subversion repository browser dialog. |
35 Class implementing the subversion repository browser dialog. |
32 """ |
36 """ |
|
37 |
33 def __init__(self, vcs, mode="browse", parent=None): |
38 def __init__(self, vcs, mode="browse", parent=None): |
34 """ |
39 """ |
35 Constructor |
40 Constructor |
36 |
41 |
37 @param vcs reference to the vcs object |
42 @param vcs reference to the vcs object |
38 @param mode mode of the dialog (string, "browse" or "select") |
43 @param mode mode of the dialog (string, "browse" or "select") |
39 @param parent parent widget (QWidget) |
44 @param parent parent widget (QWidget) |
40 """ |
45 """ |
41 super().__init__(parent) |
46 super().__init__(parent) |
42 self.setupUi(self) |
47 self.setupUi(self) |
43 self.setWindowFlags(Qt.WindowType.Window) |
48 self.setWindowFlags(Qt.WindowType.Window) |
44 |
49 |
45 self.repoTree.headerItem().setText(self.repoTree.columnCount(), "") |
50 self.repoTree.headerItem().setText(self.repoTree.columnCount(), "") |
46 self.repoTree.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder) |
51 self.repoTree.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder) |
47 |
52 |
48 self.vcs = vcs |
53 self.vcs = vcs |
49 self.mode = mode |
54 self.mode = mode |
50 |
55 |
51 self.__process = EricOverrideCursorProcess() |
56 self.__process = EricOverrideCursorProcess() |
52 self.__process.finished.connect(self.__procFinished) |
57 self.__process.finished.connect(self.__procFinished) |
53 self.__process.readyReadStandardOutput.connect(self.__readStdout) |
58 self.__process.readyReadStandardOutput.connect(self.__readStdout) |
54 self.__process.readyReadStandardError.connect(self.__readStderr) |
59 self.__process.readyReadStandardError.connect(self.__readStderr) |
55 |
60 |
56 if self.mode == "select": |
61 if self.mode == "select": |
57 self.buttonBox.button( |
62 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) |
58 QDialogButtonBox.StandardButton.Ok).setEnabled(False) |
|
59 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).hide() |
63 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).hide() |
60 else: |
64 else: |
61 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).hide() |
65 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).hide() |
62 self.buttonBox.button( |
66 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).hide() |
63 QDialogButtonBox.StandardButton.Cancel).hide() |
67 |
64 |
|
65 self.__dirIcon = UI.PixmapCache.getIcon("dirClosed") |
68 self.__dirIcon = UI.PixmapCache.getIcon("dirClosed") |
66 self.__fileIcon = UI.PixmapCache.getIcon("fileMisc") |
69 self.__fileIcon = UI.PixmapCache.getIcon("fileMisc") |
67 |
70 |
68 self.__urlRole = Qt.ItemDataRole.UserRole |
71 self.__urlRole = Qt.ItemDataRole.UserRole |
69 self.__ignoreExpand = False |
72 self.__ignoreExpand = False |
70 self.intercept = False |
73 self.intercept = False |
71 |
74 |
72 self.__rx_dir = re.compile( |
75 self.__rx_dir = re.compile( |
73 r"""\s*([0-9]+)\s+(\w+)\s+""" |
76 r"""\s*([0-9]+)\s+(\w+)\s+""" |
74 r"""((?:\w+\s+\d+|[0-9.]+\s+\w+)\s+[0-9:]+)\s+(.+)\s*""") |
77 r"""((?:\w+\s+\d+|[0-9.]+\s+\w+)\s+[0-9:]+)\s+(.+)\s*""" |
|
78 ) |
75 self.__rx_file = re.compile( |
79 self.__rx_file = re.compile( |
76 r"""\s*([0-9]+)\s+(\w+)\s+([0-9]+)\s""" |
80 r"""\s*([0-9]+)\s+(\w+)\s+([0-9]+)\s""" |
77 r"""((?:\w+\s+\d+|[0-9.]+\s+\w+)\s+[0-9:]+)\s+(.+)\s*""") |
81 r"""((?:\w+\s+\d+|[0-9.]+\s+\w+)\s+[0-9:]+)\s+(.+)\s*""" |
78 |
82 ) |
|
83 |
79 def closeEvent(self, e): |
84 def closeEvent(self, e): |
80 """ |
85 """ |
81 Protected slot implementing a close event handler. |
86 Protected slot implementing a close event handler. |
82 |
87 |
83 @param e close event (QCloseEvent) |
88 @param e close event (QCloseEvent) |
84 """ |
89 """ |
85 if ( |
90 if ( |
86 self.__process is not None and |
91 self.__process is not None |
87 self.__process.state() != QProcess.ProcessState.NotRunning |
92 and self.__process.state() != QProcess.ProcessState.NotRunning |
88 ): |
93 ): |
89 self.__process.terminate() |
94 self.__process.terminate() |
90 QTimer.singleShot(2000, self.__process.kill) |
95 QTimer.singleShot(2000, self.__process.kill) |
91 self.__process.waitForFinished(3000) |
96 self.__process.waitForFinished(3000) |
92 |
97 |
93 e.accept() |
98 e.accept() |
94 |
99 |
95 def __resort(self): |
100 def __resort(self): |
96 """ |
101 """ |
97 Private method to resort the tree. |
102 Private method to resort the tree. |
98 """ |
103 """ |
99 self.repoTree.sortItems( |
104 self.repoTree.sortItems( |
100 self.repoTree.sortColumn(), |
105 self.repoTree.sortColumn(), self.repoTree.header().sortIndicatorOrder() |
101 self.repoTree.header().sortIndicatorOrder()) |
106 ) |
102 |
107 |
103 def __resizeColumns(self): |
108 def __resizeColumns(self): |
104 """ |
109 """ |
105 Private method to resize the tree columns. |
110 Private method to resize the tree columns. |
106 """ |
111 """ |
107 self.repoTree.header().resizeSections( |
112 self.repoTree.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents) |
108 QHeaderView.ResizeMode.ResizeToContents) |
|
109 self.repoTree.header().setStretchLastSection(True) |
113 self.repoTree.header().setStretchLastSection(True) |
110 |
114 |
111 def __generateItem(self, repopath, revision, author, size, date, |
115 def __generateItem(self, repopath, revision, author, size, date, nodekind, url): |
112 nodekind, url): |
|
113 """ |
116 """ |
114 Private method to generate a tree item in the repository tree. |
117 Private method to generate a tree item in the repository tree. |
115 |
118 |
116 @param repopath path of the item (string) |
119 @param repopath path of the item (string) |
117 @param revision revision info (string) |
120 @param revision revision info (string) |
118 @param author author info (string) |
121 @param author author info (string) |
119 @param size size info (string) |
122 @param size size info (string) |
120 @param date date info (string) |
123 @param date date info (string) |
122 @param url url of the entry (string) |
125 @param url url of the entry (string) |
123 @return reference to the generated item (QTreeWidgetItem) |
126 @return reference to the generated item (QTreeWidgetItem) |
124 """ |
127 """ |
125 rev = "" if revision == "" else int(revision) |
128 rev = "" if revision == "" else int(revision) |
126 sz = "" if size == "" else int(size) |
129 sz = "" if size == "" else int(size) |
127 |
130 |
128 itm = QTreeWidgetItem(self.parentItem) |
131 itm = QTreeWidgetItem(self.parentItem) |
129 itm.setData(0, Qt.ItemDataRole.DisplayRole, repopath) |
132 itm.setData(0, Qt.ItemDataRole.DisplayRole, repopath) |
130 itm.setData(1, Qt.ItemDataRole.DisplayRole, rev) |
133 itm.setData(1, Qt.ItemDataRole.DisplayRole, rev) |
131 itm.setData(2, Qt.ItemDataRole.DisplayRole, author) |
134 itm.setData(2, Qt.ItemDataRole.DisplayRole, author) |
132 itm.setData(3, Qt.ItemDataRole.DisplayRole, sz) |
135 itm.setData(3, Qt.ItemDataRole.DisplayRole, sz) |
133 itm.setData(4, Qt.ItemDataRole.DisplayRole, date) |
136 itm.setData(4, Qt.ItemDataRole.DisplayRole, date) |
134 |
137 |
135 if nodekind == "dir": |
138 if nodekind == "dir": |
136 itm.setIcon(0, self.__dirIcon) |
139 itm.setIcon(0, self.__dirIcon) |
137 itm.setChildIndicatorPolicy( |
140 itm.setChildIndicatorPolicy( |
138 QTreeWidgetItem.ChildIndicatorPolicy.ShowIndicator) |
141 QTreeWidgetItem.ChildIndicatorPolicy.ShowIndicator |
|
142 ) |
139 elif nodekind == "file": |
143 elif nodekind == "file": |
140 itm.setIcon(0, self.__fileIcon) |
144 itm.setIcon(0, self.__fileIcon) |
141 |
145 |
142 itm.setData(0, self.__urlRole, url) |
146 itm.setData(0, self.__urlRole, url) |
143 |
147 |
144 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignLeft) |
148 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignLeft) |
145 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignRight) |
149 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignRight) |
146 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignLeft) |
150 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignLeft) |
147 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignRight) |
151 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignRight) |
148 itm.setTextAlignment(4, Qt.AlignmentFlag.AlignLeft) |
152 itm.setTextAlignment(4, Qt.AlignmentFlag.AlignLeft) |
149 |
153 |
150 return itm |
154 return itm |
151 |
155 |
152 def __repoRoot(self, url): |
156 def __repoRoot(self, url): |
153 """ |
157 """ |
154 Private method to get the repository root using the svn info command. |
158 Private method to get the repository root using the svn info command. |
155 |
159 |
156 @param url the repository URL to browser (string) |
160 @param url the repository URL to browser (string) |
157 @return repository root (string) |
161 @return repository root (string) |
158 """ |
162 """ |
159 ioEncoding = Preferences.getSystem("IOEncoding") |
163 ioEncoding = Preferences.getSystem("IOEncoding") |
160 repoRoot = None |
164 repoRoot = None |
161 |
165 |
162 process = QProcess() |
166 process = QProcess() |
163 |
167 |
164 args = [] |
168 args = [] |
165 args.append('info') |
169 args.append("info") |
166 self.vcs.addArguments(args, self.vcs.options['global']) |
170 self.vcs.addArguments(args, self.vcs.options["global"]) |
167 args.append('--xml') |
171 args.append("--xml") |
168 args.append(url) |
172 args.append(url) |
169 |
173 |
170 process.start('svn', args) |
174 process.start("svn", args) |
171 procStarted = process.waitForStarted(5000) |
175 procStarted = process.waitForStarted(5000) |
172 if procStarted: |
176 if procStarted: |
173 finished = process.waitForFinished(30000) |
177 finished = process.waitForFinished(30000) |
174 if finished: |
178 if finished: |
175 if process.exitCode() == 0: |
179 if process.exitCode() == 0: |
176 output = str(process.readAllStandardOutput(), ioEncoding, |
180 output = str(process.readAllStandardOutput(), ioEncoding, "replace") |
177 'replace') |
|
178 for line in output.splitlines(): |
181 for line in output.splitlines(): |
179 line = line.strip() |
182 line = line.strip() |
180 if line.startswith('<root>'): |
183 if line.startswith("<root>"): |
181 repoRoot = ( |
184 repoRoot = line.replace("<root>", "").replace("</root>", "") |
182 line.replace('<root>', '') |
|
183 .replace('</root>', '') |
|
184 ) |
|
185 break |
185 break |
186 else: |
186 else: |
187 error = str(process.readAllStandardError(), |
187 error = str( |
188 Preferences.getSystem("IOEncoding"), |
188 process.readAllStandardError(), |
189 'replace') |
189 Preferences.getSystem("IOEncoding"), |
|
190 "replace", |
|
191 ) |
190 self.errors.insertPlainText(error) |
192 self.errors.insertPlainText(error) |
191 self.errors.ensureCursorVisible() |
193 self.errors.ensureCursorVisible() |
192 else: |
194 else: |
193 EricMessageBox.critical( |
195 EricMessageBox.critical( |
194 self, |
196 self, |
195 self.tr('Process Generation Error'), |
197 self.tr("Process Generation Error"), |
196 self.tr( |
198 self.tr( |
197 'The process {0} could not be started. ' |
199 "The process {0} could not be started. " |
198 'Ensure, that it is in the search path.' |
200 "Ensure, that it is in the search path." |
199 ).format('svn')) |
201 ).format("svn"), |
|
202 ) |
200 return repoRoot |
203 return repoRoot |
201 |
204 |
202 def __listRepo(self, url, parent=None): |
205 def __listRepo(self, url, parent=None): |
203 """ |
206 """ |
204 Private method to perform the svn list command. |
207 Private method to perform the svn list command. |
205 |
208 |
206 @param url the repository URL to browse (string) |
209 @param url the repository URL to browse (string) |
207 @param parent reference to the item, the data should be appended to |
210 @param parent reference to the item, the data should be appended to |
208 (QTreeWidget or QTreeWidgetItem) |
211 (QTreeWidget or QTreeWidgetItem) |
209 """ |
212 """ |
210 self.errorGroup.hide() |
213 self.errorGroup.hide() |
211 |
214 |
212 self.repoUrl = url |
215 self.repoUrl = url |
213 |
216 |
214 if parent is None: |
217 if parent is None: |
215 self.parentItem = self.repoTree |
218 self.parentItem = self.repoTree |
216 else: |
219 else: |
217 self.parentItem = parent |
220 self.parentItem = parent |
218 |
221 |
219 if self.parentItem == self.repoTree: |
222 if self.parentItem == self.repoTree: |
220 repoRoot = self.__repoRoot(url) |
223 repoRoot = self.__repoRoot(url) |
221 if repoRoot is None: |
224 if repoRoot is None: |
222 self.__finish() |
225 self.__finish() |
223 return |
226 return |
224 self.__ignoreExpand = True |
227 self.__ignoreExpand = True |
225 itm = self.__generateItem( |
228 itm = self.__generateItem(repoRoot, "", "", "", "", "dir", repoRoot) |
226 repoRoot, "", "", "", "", "dir", repoRoot) |
|
227 itm.setExpanded(True) |
229 itm.setExpanded(True) |
228 self.parentItem = itm |
230 self.parentItem = itm |
229 urlPart = repoRoot |
231 urlPart = repoRoot |
230 for element in url.replace(repoRoot, "").split("/"): |
232 for element in url.replace(repoRoot, "").split("/"): |
231 if element: |
233 if element: |
232 urlPart = "{0}/{1}".format(urlPart, element) |
234 urlPart = "{0}/{1}".format(urlPart, element) |
233 itm = self.__generateItem( |
235 itm = self.__generateItem(element, "", "", "", "", "dir", urlPart) |
234 element, "", "", "", "", "dir", urlPart) |
|
235 itm.setExpanded(True) |
236 itm.setExpanded(True) |
236 self.parentItem = itm |
237 self.parentItem = itm |
237 itm.setExpanded(False) |
238 itm.setExpanded(False) |
238 self.__ignoreExpand = False |
239 self.__ignoreExpand = False |
239 self.__finish() |
240 self.__finish() |
240 return |
241 return |
241 |
242 |
242 self.intercept = False |
243 self.intercept = False |
243 |
244 |
244 self.__process.kill() |
245 self.__process.kill() |
245 |
246 |
246 args = [] |
247 args = [] |
247 args.append('list') |
248 args.append("list") |
248 self.vcs.addArguments(args, self.vcs.options['global']) |
249 self.vcs.addArguments(args, self.vcs.options["global"]) |
249 if '--verbose' not in self.vcs.options['global']: |
250 if "--verbose" not in self.vcs.options["global"]: |
250 args.append('--verbose') |
251 args.append("--verbose") |
251 args.append(url) |
252 args.append(url) |
252 |
253 |
253 self.__process.start('svn', args) |
254 self.__process.start("svn", args) |
254 procStarted = self.__process.waitForStarted(5000) |
255 procStarted = self.__process.waitForStarted(5000) |
255 if not procStarted: |
256 if not procStarted: |
256 self.__finish() |
257 self.__finish() |
257 self.inputGroup.setEnabled(False) |
258 self.inputGroup.setEnabled(False) |
258 self.inputGroup.hide() |
259 self.inputGroup.hide() |
259 EricMessageBox.critical( |
260 EricMessageBox.critical( |
260 self, |
261 self, |
261 self.tr('Process Generation Error'), |
262 self.tr("Process Generation Error"), |
262 self.tr( |
263 self.tr( |
263 'The process {0} could not be started. ' |
264 "The process {0} could not be started. " |
264 'Ensure, that it is in the search path.' |
265 "Ensure, that it is in the search path." |
265 ).format('svn')) |
266 ).format("svn"), |
|
267 ) |
266 else: |
268 else: |
267 self.inputGroup.setEnabled(True) |
269 self.inputGroup.setEnabled(True) |
268 self.inputGroup.show() |
270 self.inputGroup.show() |
269 |
271 |
270 def __normalizeUrl(self, url): |
272 def __normalizeUrl(self, url): |
271 """ |
273 """ |
272 Private method to normalite the url. |
274 Private method to normalite the url. |
273 |
275 |
274 @param url the url to normalize (string) |
276 @param url the url to normalize (string) |
275 @return normalized URL (string) |
277 @return normalized URL (string) |
276 """ |
278 """ |
277 if url.endswith("/"): |
279 if url.endswith("/"): |
278 return url[:-1] |
280 return url[:-1] |
279 return url |
281 return url |
280 |
282 |
281 def start(self, url): |
283 def start(self, url): |
282 """ |
284 """ |
283 Public slot to start the svn info command. |
285 Public slot to start the svn info command. |
284 |
286 |
285 @param url the repository URL to browser (string) |
287 @param url the repository URL to browser (string) |
286 """ |
288 """ |
287 self.repoTree.clear() |
289 self.repoTree.clear() |
288 |
290 |
289 self.url = "" |
291 self.url = "" |
290 |
292 |
291 url = self.__normalizeUrl(url) |
293 url = self.__normalizeUrl(url) |
292 if self.urlCombo.findText(url) == -1: |
294 if self.urlCombo.findText(url) == -1: |
293 self.urlCombo.addItem(url) |
295 self.urlCombo.addItem(url) |
294 |
296 |
295 @pyqtSlot(int) |
297 @pyqtSlot(int) |
296 def on_urlCombo_currentIndexChanged(self, index): |
298 def on_urlCombo_currentIndexChanged(self, index): |
297 """ |
299 """ |
298 Private slot called, when a new repository URL is entered or selected. |
300 Private slot called, when a new repository URL is entered or selected. |
299 |
301 |
300 @param index index of the current item |
302 @param index index of the current item |
301 @type int |
303 @type int |
302 """ |
304 """ |
303 text = self.urlCombo.itemText(index) |
305 text = self.urlCombo.itemText(index) |
304 url = self.__normalizeUrl(text) |
306 url = self.__normalizeUrl(text) |
305 if url != self.url: |
307 if url != self.url: |
306 self.url = url |
308 self.url = url |
307 self.repoTree.clear() |
309 self.repoTree.clear() |
308 self.__listRepo(url) |
310 self.__listRepo(url) |
309 |
311 |
310 @pyqtSlot(QTreeWidgetItem) |
312 @pyqtSlot(QTreeWidgetItem) |
311 def on_repoTree_itemExpanded(self, item): |
313 def on_repoTree_itemExpanded(self, item): |
312 """ |
314 """ |
313 Private slot called when an item is expanded. |
315 Private slot called when an item is expanded. |
314 |
316 |
315 @param item reference to the item to be expanded (QTreeWidgetItem) |
317 @param item reference to the item to be expanded (QTreeWidgetItem) |
316 """ |
318 """ |
317 if not self.__ignoreExpand: |
319 if not self.__ignoreExpand: |
318 url = item.data(0, self.__urlRole) |
320 url = item.data(0, self.__urlRole) |
319 self.__listRepo(url, item) |
321 self.__listRepo(url, item) |
320 |
322 |
321 @pyqtSlot(QTreeWidgetItem) |
323 @pyqtSlot(QTreeWidgetItem) |
322 def on_repoTree_itemCollapsed(self, item): |
324 def on_repoTree_itemCollapsed(self, item): |
323 """ |
325 """ |
324 Private slot called when an item is collapsed. |
326 Private slot called when an item is collapsed. |
325 |
327 |
326 @param item reference to the item to be collapsed (QTreeWidgetItem) |
328 @param item reference to the item to be collapsed (QTreeWidgetItem) |
327 """ |
329 """ |
328 for child in item.takeChildren(): |
330 for child in item.takeChildren(): |
329 del child |
331 del child |
330 |
332 |
331 @pyqtSlot() |
333 @pyqtSlot() |
332 def on_repoTree_itemSelectionChanged(self): |
334 def on_repoTree_itemSelectionChanged(self): |
333 """ |
335 """ |
334 Private slot called when the selection changes. |
336 Private slot called when the selection changes. |
335 """ |
337 """ |
336 if self.mode == "select": |
338 if self.mode == "select": |
337 self.buttonBox.button( |
339 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True) |
338 QDialogButtonBox.StandardButton.Ok).setEnabled(True) |
340 |
339 |
|
340 def accept(self): |
341 def accept(self): |
341 """ |
342 """ |
342 Public slot called when the dialog is accepted. |
343 Public slot called when the dialog is accepted. |
343 """ |
344 """ |
344 if self.focusWidget() == self.urlCombo: |
345 if self.focusWidget() == self.urlCombo: |
345 return |
346 return |
346 |
347 |
347 super().accept() |
348 super().accept() |
348 |
349 |
349 def getSelectedUrl(self): |
350 def getSelectedUrl(self): |
350 """ |
351 """ |
351 Public method to retrieve the selected repository URL. |
352 Public method to retrieve the selected repository URL. |
352 |
353 |
353 @return the selected repository URL (string) |
354 @return the selected repository URL (string) |
354 """ |
355 """ |
355 items = self.repoTree.selectedItems() |
356 items = self.repoTree.selectedItems() |
356 if len(items) == 1: |
357 if len(items) == 1: |
357 return items[0].data(0, self.__urlRole) |
358 return items[0].data(0, self.__urlRole) |
358 else: |
359 else: |
359 return "" |
360 return "" |
360 |
361 |
361 def __finish(self): |
362 def __finish(self): |
362 """ |
363 """ |
363 Private slot called when the process finished or the user pressed the |
364 Private slot called when the process finished or the user pressed the |
364 button. |
365 button. |
365 """ |
366 """ |
366 if ( |
367 if ( |
367 self.__process is not None and |
368 self.__process is not None |
368 self.__process.state() != QProcess.ProcessState.NotRunning |
369 and self.__process.state() != QProcess.ProcessState.NotRunning |
369 ): |
370 ): |
370 self.__process.terminate() |
371 self.__process.terminate() |
371 QTimer.singleShot(2000, self.__process.kill) |
372 QTimer.singleShot(2000, self.__process.kill) |
372 self.__process.waitForFinished(3000) |
373 self.__process.waitForFinished(3000) |
373 |
374 |
374 self.inputGroup.setEnabled(False) |
375 self.inputGroup.setEnabled(False) |
375 self.inputGroup.hide() |
376 self.inputGroup.hide() |
376 |
377 |
377 self.__resizeColumns() |
378 self.__resizeColumns() |
378 self.__resort() |
379 self.__resort() |
379 |
380 |
380 def __procFinished(self, exitCode, exitStatus): |
381 def __procFinished(self, exitCode, exitStatus): |
381 """ |
382 """ |
382 Private slot connected to the finished signal. |
383 Private slot connected to the finished signal. |
383 |
384 |
384 @param exitCode exit code of the process (integer) |
385 @param exitCode exit code of the process (integer) |
385 @param exitStatus exit status of the process (QProcess.ExitStatus) |
386 @param exitStatus exit status of the process (QProcess.ExitStatus) |
386 """ |
387 """ |
387 self.__finish() |
388 self.__finish() |
388 |
389 |
389 def __readStdout(self): |
390 def __readStdout(self): |
390 """ |
391 """ |
391 Private slot to handle the readyReadStandardOutput signal. |
392 Private slot to handle the readyReadStandardOutput signal. |
392 |
393 |
393 It reads the output of the process, formats it and inserts it into |
394 It reads the output of the process, formats it and inserts it into |
394 the contents pane. |
395 the contents pane. |
395 """ |
396 """ |
396 if self.__process is not None: |
397 if self.__process is not None: |
397 self.__process.setReadChannel( |
398 self.__process.setReadChannel(QProcess.ProcessChannel.StandardOutput) |
398 QProcess.ProcessChannel.StandardOutput) |
399 |
399 |
|
400 while self.__process.canReadLine(): |
400 while self.__process.canReadLine(): |
401 s = str(self.__process.readLine(), |
401 s = str( |
402 Preferences.getSystem("IOEncoding"), |
402 self.__process.readLine(), |
403 'replace') |
403 Preferences.getSystem("IOEncoding"), |
404 match = ( |
404 "replace", |
405 self.__rx_dir.fullmatch(s) or |
|
406 self.__rx_file.fullmatch(s) |
|
407 ) |
405 ) |
|
406 match = self.__rx_dir.fullmatch(s) or self.__rx_file.fullmatch(s) |
408 if match is None: |
407 if match is None: |
409 continue |
408 continue |
410 elif match.re is self.__rx_dir: |
409 elif match.re is self.__rx_dir: |
411 revision = match.group(1) |
410 revision = match.group(1) |
412 author = match.group(2) |
411 author = match.group(2) |
423 author = match.group(2) |
422 author = match.group(2) |
424 size = match.group(3) |
423 size = match.group(3) |
425 date = match.group(4) |
424 date = match.group(4) |
426 name = match.group(5).strip() |
425 name = match.group(5).strip() |
427 nodekind = "file" |
426 nodekind = "file" |
428 |
427 |
429 url = "{0}/{1}".format(self.repoUrl, name) |
428 url = "{0}/{1}".format(self.repoUrl, name) |
430 self.__generateItem( |
429 self.__generateItem(name, revision, author, size, date, nodekind, url) |
431 name, revision, author, size, date, nodekind, url) |
430 |
432 |
|
433 def __readStderr(self): |
431 def __readStderr(self): |
434 """ |
432 """ |
435 Private slot to handle the readyReadStandardError signal. |
433 Private slot to handle the readyReadStandardError signal. |
436 |
434 |
437 It reads the error output of the process and inserts it into the |
435 It reads the error output of the process and inserts it into the |
438 error pane. |
436 error pane. |
439 """ |
437 """ |
440 if self.__process is not None: |
438 if self.__process is not None: |
441 s = str(self.__process.readAllStandardError(), |
439 s = str( |
442 Preferences.getSystem("IOEncoding"), |
440 self.__process.readAllStandardError(), |
443 'replace') |
441 Preferences.getSystem("IOEncoding"), |
|
442 "replace", |
|
443 ) |
444 self.errors.insertPlainText(s) |
444 self.errors.insertPlainText(s) |
445 self.errors.ensureCursorVisible() |
445 self.errors.ensureCursorVisible() |
446 self.errorGroup.show() |
446 self.errorGroup.show() |
447 |
447 |
448 def on_passwordCheckBox_toggled(self, isOn): |
448 def on_passwordCheckBox_toggled(self, isOn): |
449 """ |
449 """ |
450 Private slot to handle the password checkbox toggled. |
450 Private slot to handle the password checkbox toggled. |
451 |
451 |
452 @param isOn flag indicating the status of the check box (boolean) |
452 @param isOn flag indicating the status of the check box (boolean) |
453 """ |
453 """ |
454 if isOn: |
454 if isOn: |
455 self.input.setEchoMode(QLineEdit.EchoMode.Password) |
455 self.input.setEchoMode(QLineEdit.EchoMode.Password) |
456 else: |
456 else: |
457 self.input.setEchoMode(QLineEdit.EchoMode.Normal) |
457 self.input.setEchoMode(QLineEdit.EchoMode.Normal) |
458 |
458 |
459 @pyqtSlot() |
459 @pyqtSlot() |
460 def on_sendButton_clicked(self): |
460 def on_sendButton_clicked(self): |
461 """ |
461 """ |
462 Private slot to send the input to the subversion process. |
462 Private slot to send the input to the subversion process. |
463 """ |
463 """ |
464 inputTxt = self.input.text() |
464 inputTxt = self.input.text() |
465 inputTxt += os.linesep |
465 inputTxt += os.linesep |
466 |
466 |
467 if self.passwordCheckBox.isChecked(): |
467 if self.passwordCheckBox.isChecked(): |
468 self.errors.insertPlainText(os.linesep) |
468 self.errors.insertPlainText(os.linesep) |
469 self.errors.ensureCursorVisible() |
469 self.errors.ensureCursorVisible() |
470 else: |
470 else: |
471 self.errors.insertPlainText(inputTxt) |
471 self.errors.insertPlainText(inputTxt) |
472 self.errors.ensureCursorVisible() |
472 self.errors.ensureCursorVisible() |
473 |
473 |
474 self.__process.write(strToQByteArray(inputTxt)) |
474 self.__process.write(strToQByteArray(inputTxt)) |
475 |
475 |
476 self.passwordCheckBox.setChecked(False) |
476 self.passwordCheckBox.setChecked(False) |
477 self.input.clear() |
477 self.input.clear() |
478 |
478 |
479 def on_input_returnPressed(self): |
479 def on_input_returnPressed(self): |
480 """ |
480 """ |
481 Private slot to handle the press of the return key in the input field. |
481 Private slot to handle the press of the return key in the input field. |
482 """ |
482 """ |
483 self.intercept = True |
483 self.intercept = True |
484 self.on_sendButton_clicked() |
484 self.on_sendButton_clicked() |
485 |
485 |
486 def keyPressEvent(self, evt): |
486 def keyPressEvent(self, evt): |
487 """ |
487 """ |
488 Protected slot to handle a key press event. |
488 Protected slot to handle a key press event. |
489 |
489 |
490 @param evt the key press event (QKeyEvent) |
490 @param evt the key press event (QKeyEvent) |
491 """ |
491 """ |
492 if self.intercept: |
492 if self.intercept: |
493 self.intercept = False |
493 self.intercept = False |
494 evt.accept() |
494 evt.accept() |