eric6/Plugins/VcsPlugins/vcsPySvn/SvnRepoBrowserDialog.py

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

eric ide

mercurial