29 |
33 |
30 class SvnRepoBrowserDialog(QDialog, SvnDialogMixin, Ui_SvnRepoBrowserDialog): |
34 class SvnRepoBrowserDialog(QDialog, SvnDialogMixin, Ui_SvnRepoBrowserDialog): |
31 """ |
35 """ |
32 Class implementing the subversion repository browser dialog. |
36 Class implementing the subversion repository browser dialog. |
33 """ |
37 """ |
|
38 |
34 def __init__(self, vcs, mode="browse", parent=None): |
39 def __init__(self, vcs, mode="browse", parent=None): |
35 """ |
40 """ |
36 Constructor |
41 Constructor |
37 |
42 |
38 @param vcs reference to the vcs object |
43 @param vcs reference to the vcs object |
39 @param mode mode of the dialog (string, "browse" or "select") |
44 @param mode mode of the dialog (string, "browse" or "select") |
40 @param parent parent widget (QWidget) |
45 @param parent parent widget (QWidget) |
41 """ |
46 """ |
42 super().__init__(parent) |
47 super().__init__(parent) |
43 self.setupUi(self) |
48 self.setupUi(self) |
44 SvnDialogMixin.__init__(self) |
49 SvnDialogMixin.__init__(self) |
45 self.setWindowFlags(Qt.WindowType.Window) |
50 self.setWindowFlags(Qt.WindowType.Window) |
46 |
51 |
47 self.repoTree.headerItem().setText(self.repoTree.columnCount(), "") |
52 self.repoTree.headerItem().setText(self.repoTree.columnCount(), "") |
48 self.repoTree.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder) |
53 self.repoTree.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder) |
49 |
54 |
50 self.vcs = vcs |
55 self.vcs = vcs |
51 self.mode = mode |
56 self.mode = mode |
52 |
57 |
53 if self.mode == "select": |
58 if self.mode == "select": |
54 self.buttonBox.button( |
59 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) |
55 QDialogButtonBox.StandardButton.Ok).setEnabled(False) |
|
56 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).hide() |
60 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).hide() |
57 else: |
61 else: |
58 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).hide() |
62 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).hide() |
59 self.buttonBox.button( |
63 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).hide() |
60 QDialogButtonBox.StandardButton.Cancel).hide() |
64 |
61 |
|
62 self.__dirIcon = UI.PixmapCache.getIcon("dirClosed") |
65 self.__dirIcon = UI.PixmapCache.getIcon("dirClosed") |
63 self.__fileIcon = UI.PixmapCache.getIcon("fileMisc") |
66 self.__fileIcon = UI.PixmapCache.getIcon("fileMisc") |
64 |
67 |
65 self.__urlRole = Qt.ItemDataRole.UserRole |
68 self.__urlRole = Qt.ItemDataRole.UserRole |
66 self.__ignoreExpand = False |
69 self.__ignoreExpand = False |
67 |
70 |
68 self.client = self.vcs.getClient() |
71 self.client = self.vcs.getClient() |
69 self.client.callback_cancel = self._clientCancelCallback |
72 self.client.callback_cancel = self._clientCancelCallback |
70 self.client.callback_get_login = self._clientLoginCallback |
73 self.client.callback_get_login = self._clientLoginCallback |
71 self.client.callback_ssl_server_trust_prompt = ( |
74 self.client.callback_ssl_server_trust_prompt = ( |
72 self._clientSslServerTrustPromptCallback |
75 self._clientSslServerTrustPromptCallback |
73 ) |
76 ) |
74 |
77 |
75 self.show() |
78 self.show() |
76 QApplication.processEvents() |
79 QApplication.processEvents() |
77 |
80 |
78 def __resort(self): |
81 def __resort(self): |
79 """ |
82 """ |
80 Private method to resort the tree. |
83 Private method to resort the tree. |
81 """ |
84 """ |
82 self.repoTree.sortItems( |
85 self.repoTree.sortItems( |
83 self.repoTree.sortColumn(), |
86 self.repoTree.sortColumn(), self.repoTree.header().sortIndicatorOrder() |
84 self.repoTree.header().sortIndicatorOrder()) |
87 ) |
85 |
88 |
86 def __resizeColumns(self): |
89 def __resizeColumns(self): |
87 """ |
90 """ |
88 Private method to resize the tree columns. |
91 Private method to resize the tree columns. |
89 """ |
92 """ |
90 self.repoTree.header().resizeSections( |
93 self.repoTree.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents) |
91 QHeaderView.ResizeMode.ResizeToContents) |
|
92 self.repoTree.header().setStretchLastSection(True) |
94 self.repoTree.header().setStretchLastSection(True) |
93 |
95 |
94 def __generateItem(self, parent, repopath, revision, author, size, date, |
96 def __generateItem( |
95 nodekind, url): |
97 self, parent, repopath, revision, author, size, date, nodekind, url |
|
98 ): |
96 """ |
99 """ |
97 Private method to generate a tree item in the repository tree. |
100 Private method to generate a tree item in the repository tree. |
98 |
101 |
99 @param parent parent of the item to be created (QTreeWidget or |
102 @param parent parent of the item to be created (QTreeWidget or |
100 QTreeWidgetItem) |
103 QTreeWidgetItem) |
101 @param repopath path of the item (string) |
104 @param repopath path of the item (string) |
102 @param revision revision info (string or pysvn.opt_revision_kind) |
105 @param revision revision info (string or pysvn.opt_revision_kind) |
103 @param author author info (string) |
106 @param author author info (string) |
106 @param nodekind node kind info (pysvn.node_kind) |
109 @param nodekind node kind info (pysvn.node_kind) |
107 @param url url of the entry (string) |
110 @param url url of the entry (string) |
108 @return reference to the generated item (QTreeWidgetItem) |
111 @return reference to the generated item (QTreeWidgetItem) |
109 """ |
112 """ |
110 path = url if repopath == "/" else url.split("/")[-1] |
113 path = url if repopath == "/" else url.split("/")[-1] |
111 |
114 |
112 rev = revision.number if revision else "" |
115 rev = revision.number if revision else "" |
113 dt = formatTime(date) if date else "" |
116 dt = formatTime(date) if date else "" |
114 if author is None: |
117 if author is None: |
115 author = "" |
118 author = "" |
116 |
119 |
117 itm = QTreeWidgetItem(parent) |
120 itm = QTreeWidgetItem(parent) |
118 itm.setData(0, Qt.ItemDataRole.DisplayRole, path) |
121 itm.setData(0, Qt.ItemDataRole.DisplayRole, path) |
119 itm.setData(1, Qt.ItemDataRole.DisplayRole, rev) |
122 itm.setData(1, Qt.ItemDataRole.DisplayRole, rev) |
120 itm.setData(2, Qt.ItemDataRole.DisplayRole, author) |
123 itm.setData(2, Qt.ItemDataRole.DisplayRole, author) |
121 itm.setData(3, Qt.ItemDataRole.DisplayRole, size) |
124 itm.setData(3, Qt.ItemDataRole.DisplayRole, size) |
122 itm.setData(4, Qt.ItemDataRole.DisplayRole, dt) |
125 itm.setData(4, Qt.ItemDataRole.DisplayRole, dt) |
123 |
126 |
124 if nodekind == pysvn.node_kind.dir: |
127 if nodekind == pysvn.node_kind.dir: |
125 itm.setIcon(0, self.__dirIcon) |
128 itm.setIcon(0, self.__dirIcon) |
126 itm.setChildIndicatorPolicy( |
129 itm.setChildIndicatorPolicy( |
127 QTreeWidgetItem.ChildIndicatorPolicy.ShowIndicator) |
130 QTreeWidgetItem.ChildIndicatorPolicy.ShowIndicator |
|
131 ) |
128 elif nodekind == pysvn.node_kind.file: |
132 elif nodekind == pysvn.node_kind.file: |
129 itm.setIcon(0, self.__fileIcon) |
133 itm.setIcon(0, self.__fileIcon) |
130 |
134 |
131 itm.setData(0, self.__urlRole, url) |
135 itm.setData(0, self.__urlRole, url) |
132 |
136 |
133 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignLeft) |
137 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignLeft) |
134 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignRight) |
138 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignRight) |
135 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignLeft) |
139 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignLeft) |
136 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignRight) |
140 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignRight) |
137 itm.setTextAlignment(4, Qt.AlignmentFlag.AlignLeft) |
141 itm.setTextAlignment(4, Qt.AlignmentFlag.AlignLeft) |
138 |
142 |
139 return itm |
143 return itm |
140 |
144 |
141 def __listRepo(self, url, parent=None): |
145 def __listRepo(self, url, parent=None): |
142 """ |
146 """ |
143 Private method to perform the svn list command. |
147 Private method to perform the svn list command. |
144 |
148 |
145 @param url the repository URL to browser (string) |
149 @param url the repository URL to browser (string) |
146 @param parent reference to the item, the data should be appended to |
150 @param parent reference to the item, the data should be appended to |
147 (QTreeWidget or QTreeWidgetItem) |
151 (QTreeWidget or QTreeWidgetItem) |
148 """ |
152 """ |
149 if parent is None: |
153 if parent is None: |
150 parent = self.repoTree |
154 parent = self.repoTree |
151 |
155 |
152 with EricOverrideCursor(): |
156 with EricOverrideCursor(): |
153 try: |
157 try: |
154 with EricMutexLocker(self.vcs.vcsExecutionMutex): |
158 with EricMutexLocker(self.vcs.vcsExecutionMutex): |
155 entries = self.client.list(url, recurse=False) |
159 entries = self.client.list(url, recurse=False) |
156 firstTime = parent == self.repoTree |
160 firstTime = parent == self.repoTree |
157 for dirent, _lock in entries: |
161 for dirent, _lock in entries: |
158 if ( |
162 if (firstTime and dirent["path"] != url) or ( |
159 (firstTime and dirent["path"] != url) or |
163 parent != self.repoTree and dirent["path"] == url |
160 (parent != self.repoTree and dirent["path"] == url) |
|
161 ): |
164 ): |
162 continue |
165 continue |
163 if firstTime: |
166 if firstTime: |
164 if dirent["repos_path"] != "/": |
167 if dirent["repos_path"] != "/": |
165 repoUrl = dirent["path"].replace( |
168 repoUrl = dirent["path"].replace(dirent["repos_path"], "") |
166 dirent["repos_path"], "") |
|
167 else: |
169 else: |
168 repoUrl = dirent["path"] |
170 repoUrl = dirent["path"] |
169 if repoUrl != url: |
171 if repoUrl != url: |
170 self.__ignoreExpand = True |
172 self.__ignoreExpand = True |
171 itm = self.__generateItem( |
173 itm = self.__generateItem( |
172 parent, "/", "", "", 0, "", |
174 parent, "/", "", "", 0, "", pysvn.node_kind.dir, repoUrl |
173 pysvn.node_kind.dir, repoUrl) |
175 ) |
174 itm.setExpanded(True) |
176 itm.setExpanded(True) |
175 parent = itm |
177 parent = itm |
176 urlPart = repoUrl |
178 urlPart = repoUrl |
177 for element in ( |
179 for element in dirent["repos_path"].split("/")[:-1]: |
178 dirent["repos_path"].split("/")[:-1] |
|
179 ): |
|
180 if element: |
180 if element: |
181 urlPart = "{0}/{1}".format(urlPart, |
181 urlPart = "{0}/{1}".format(urlPart, element) |
182 element) |
|
183 itm = self.__generateItem( |
182 itm = self.__generateItem( |
184 parent, element, "", "", 0, "", |
183 parent, |
185 pysvn.node_kind.dir, urlPart) |
184 element, |
|
185 "", |
|
186 "", |
|
187 0, |
|
188 "", |
|
189 pysvn.node_kind.dir, |
|
190 urlPart, |
|
191 ) |
186 itm.setExpanded(True) |
192 itm.setExpanded(True) |
187 parent = itm |
193 parent = itm |
188 self.__ignoreExpand = False |
194 self.__ignoreExpand = False |
189 itm = self.__generateItem( |
195 itm = self.__generateItem( |
190 parent, dirent["repos_path"], |
196 parent, |
191 dirent["created_rev"], dirent["last_author"], |
197 dirent["repos_path"], |
192 dirent["size"], dirent["time"], dirent["kind"], |
198 dirent["created_rev"], |
193 dirent["path"]) |
199 dirent["last_author"], |
|
200 dirent["size"], |
|
201 dirent["time"], |
|
202 dirent["kind"], |
|
203 dirent["path"], |
|
204 ) |
194 self.__resort() |
205 self.__resort() |
195 self.__resizeColumns() |
206 self.__resizeColumns() |
196 except pysvn.ClientError as e: |
207 except pysvn.ClientError as e: |
197 self.__showError(e.args[0]) |
208 self.__showError(e.args[0]) |
198 except AttributeError: |
209 except AttributeError: |
199 self.__showError( |
210 self.__showError( |
200 self.tr("The installed version of PySvn should be " |
211 self.tr( |
201 "1.4.0 or better.")) |
212 "The installed version of PySvn should be " "1.4.0 or better." |
202 |
213 ) |
|
214 ) |
|
215 |
203 def __normalizeUrl(self, url): |
216 def __normalizeUrl(self, url): |
204 """ |
217 """ |
205 Private method to normalite the url. |
218 Private method to normalite the url. |
206 |
219 |
207 @param url the url to normalize (string) |
220 @param url the url to normalize (string) |
208 @return normalized URL (string) |
221 @return normalized URL (string) |
209 """ |
222 """ |
210 if url.endswith("/"): |
223 if url.endswith("/"): |
211 return url[:-1] |
224 return url[:-1] |
212 return url |
225 return url |
213 |
226 |
214 def start(self, url): |
227 def start(self, url): |
215 """ |
228 """ |
216 Public slot to start the svn info command. |
229 Public slot to start the svn info command. |
217 |
230 |
218 @param url the repository URL to browser (string) |
231 @param url the repository URL to browser (string) |
219 """ |
232 """ |
220 self.repoTree.clear() |
233 self.repoTree.clear() |
221 |
234 |
222 self.url = "" |
235 self.url = "" |
223 |
236 |
224 url = self.__normalizeUrl(url) |
237 url = self.__normalizeUrl(url) |
225 if self.urlCombo.findText(url) == -1: |
238 if self.urlCombo.findText(url) == -1: |
226 self.urlCombo.addItem(url) |
239 self.urlCombo.addItem(url) |
227 |
240 |
228 @pyqtSlot(int) |
241 @pyqtSlot(int) |
229 def on_urlCombo_currentIndexChanged(self, index): |
242 def on_urlCombo_currentIndexChanged(self, index): |
230 """ |
243 """ |
231 Private slot called, when a new repository URL is entered or selected. |
244 Private slot called, when a new repository URL is entered or selected. |
232 |
245 |
233 @param index of the current item |
246 @param index of the current item |
234 @type int |
247 @type int |
235 """ |
248 """ |
236 text = self.urlCombo.itemText(index) |
249 text = self.urlCombo.itemText(index) |
237 url = self.__normalizeUrl(text) |
250 url = self.__normalizeUrl(text) |
238 if url != self.url: |
251 if url != self.url: |
239 self.url = url |
252 self.url = url |
240 self.repoTree.clear() |
253 self.repoTree.clear() |
241 self.__listRepo(url) |
254 self.__listRepo(url) |
242 |
255 |
243 @pyqtSlot(QTreeWidgetItem) |
256 @pyqtSlot(QTreeWidgetItem) |
244 def on_repoTree_itemExpanded(self, item): |
257 def on_repoTree_itemExpanded(self, item): |
245 """ |
258 """ |
246 Private slot called when an item is expanded. |
259 Private slot called when an item is expanded. |
247 |
260 |
248 @param item reference to the item to be expanded (QTreeWidgetItem) |
261 @param item reference to the item to be expanded (QTreeWidgetItem) |
249 """ |
262 """ |
250 if not self.__ignoreExpand: |
263 if not self.__ignoreExpand: |
251 url = item.data(0, self.__urlRole) |
264 url = item.data(0, self.__urlRole) |
252 self.__listRepo(url, item) |
265 self.__listRepo(url, item) |
253 |
266 |
254 @pyqtSlot(QTreeWidgetItem) |
267 @pyqtSlot(QTreeWidgetItem) |
255 def on_repoTree_itemCollapsed(self, item): |
268 def on_repoTree_itemCollapsed(self, item): |
256 """ |
269 """ |
257 Private slot called when an item is collapsed. |
270 Private slot called when an item is collapsed. |
258 |
271 |
259 @param item reference to the item to be collapsed (QTreeWidgetItem) |
272 @param item reference to the item to be collapsed (QTreeWidgetItem) |
260 """ |
273 """ |
261 for child in item.takeChildren(): |
274 for child in item.takeChildren(): |
262 del child |
275 del child |
263 |
276 |
264 @pyqtSlot() |
277 @pyqtSlot() |
265 def on_repoTree_itemSelectionChanged(self): |
278 def on_repoTree_itemSelectionChanged(self): |
266 """ |
279 """ |
267 Private slot called when the selection changes. |
280 Private slot called when the selection changes. |
268 """ |
281 """ |
269 if self.mode == "select": |
282 if self.mode == "select": |
270 self.buttonBox.button( |
283 self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(True) |
271 QDialogButtonBox.StandardButton.Ok).setEnabled(True) |
284 |
272 |
|
273 def __showError(self, msg): |
285 def __showError(self, msg): |
274 """ |
286 """ |
275 Private slot to show an error message. |
287 Private slot to show an error message. |
276 |
288 |
277 @param msg error message to show (string) |
289 @param msg error message to show (string) |
278 """ |
290 """ |
279 EricMessageBox.critical( |
291 EricMessageBox.critical(self, self.tr("Subversion Error"), msg) |
280 self, |
292 |
281 self.tr("Subversion Error"), |
|
282 msg) |
|
283 |
|
284 def accept(self): |
293 def accept(self): |
285 """ |
294 """ |
286 Public slot called when the dialog is accepted. |
295 Public slot called when the dialog is accepted. |
287 """ |
296 """ |
288 if self.focusWidget() == self.urlCombo: |
297 if self.focusWidget() == self.urlCombo: |
289 return |
298 return |
290 |
299 |
291 super().accept() |
300 super().accept() |
292 |
301 |
293 def getSelectedUrl(self): |
302 def getSelectedUrl(self): |
294 """ |
303 """ |
295 Public method to retrieve the selected repository URL. |
304 Public method to retrieve the selected repository URL. |
296 |
305 |
297 @return the selected repository URL (string) |
306 @return the selected repository URL (string) |
298 """ |
307 """ |
299 items = self.repoTree.selectedItems() |
308 items = self.repoTree.selectedItems() |
300 if len(items) == 1: |
309 if len(items) == 1: |
301 return items[0].data(0, self.__urlRole) |
310 return items[0].data(0, self.__urlRole) |