Plugins/VcsPlugins/vcsPySvn/SvnLogDialog.py

changeset 0
de9c2efb9d02
child 12
1d8dd9706f46
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2003 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show the output of the svn log command process.
8 """
9
10 import os
11 import sys
12
13 import pysvn
14
15 from PyQt4.QtCore import *
16 from PyQt4.QtGui import *
17
18 from SvnUtilities import formatTime
19
20 from SvnDialogMixin import SvnDialogMixin
21 from Ui_SvnLogDialog import Ui_SvnLogDialog
22 from SvnDiffDialog import SvnDiffDialog
23
24 import Utilities
25
26 class SvnLogDialog(QWidget, SvnDialogMixin, Ui_SvnLogDialog):
27 """
28 Class implementing a dialog to show the output of the svn log command.
29
30 The dialog is nonmodal. Clicking a link in the upper text pane shows
31 a diff of the versions.
32 """
33 def __init__(self, vcs, parent = None):
34 """
35 Constructor
36
37 @param vcs reference to the vcs object
38 @param parent parent widget (QWidget)
39 """
40 QWidget.__init__(self, parent)
41 self.setupUi(self)
42 SvnDialogMixin.__init__(self)
43
44 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
45 self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
46
47 self.vcs = vcs
48
49 self.contents.setHtml(\
50 self.trUtf8('<b>Processing your request, please wait...</b>'))
51
52 self.connect(self.contents, SIGNAL('anchorClicked(const QUrl&)'),
53 self.__sourceChanged)
54
55 self.flags = {
56 'A' : self.trUtf8('Added'),
57 'D' : self.trUtf8('Deleted'),
58 'M' : self.trUtf8('Modified')
59 }
60
61 self.revString = self.trUtf8('revision')
62 self.diff = None
63
64 self.client = self.vcs.getClient()
65 self.client.callback_cancel = \
66 self._clientCancelCallback
67 self.client.callback_get_login = \
68 self._clientLoginCallback
69 self.client.callback_ssl_server_trust_prompt = \
70 self._clientSslServerTrustPromptCallback
71
72 def start(self, fn, noEntries = 0):
73 """
74 Public slot to start the svn log command.
75
76 @param fn filename to show the log for (string)
77 @param noEntries number of entries to show (integer)
78 """
79 self.errorGroup.hide()
80
81 fetchLimit = 10
82
83 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
84 QApplication.processEvents()
85
86 self.filename = fn
87 dname, fname = self.vcs.splitPath(fn)
88
89 opts = self.vcs.options['global'] + self.vcs.options['log']
90 verbose = "--verbose" in opts
91
92 self.activateWindow()
93 self.raise_()
94
95 locker = QMutexLocker(self.vcs.vcsExecutionMutex)
96 cwd = os.getcwd()
97 os.chdir(dname)
98 try:
99 fetched = 0
100 logs = []
101 limit = noEntries or 9999999
102 while fetched < limit:
103 flimit = min(fetchLimit, limit - fetched)
104 if fetched == 0:
105 revstart = pysvn.Revision(pysvn.opt_revision_kind.head)
106 else:
107 revstart = pysvn.Revision(\
108 pysvn.opt_revision_kind.number, nextRev)
109 allLogs = self.client.log(fname,
110 revision_start = revstart,
111 discover_changed_paths = verbose,
112 limit = flimit + 1,
113 strict_node_history = False)
114 if len(allLogs) <= flimit or self._clientCancelCallback():
115 logs.extend(allLogs)
116 break
117 else:
118 logs.extend(allLogs[:-1])
119 nextRev = allLogs[-1]["revision"].number
120 fetched += fetchLimit
121 locker.unlock()
122
123 self.contents.clear()
124 self.__pegRev = None
125 for log in logs:
126 ver = "%d" % log["revision"].number
127 dstr = '<b>{0} {1}</b>'.format(self.revString, ver)
128 if self.__pegRev is None:
129 self.__pegRev = int(ver)
130 try:
131 lv = "%d" % logs[logs.index(log) + 1]["revision"].number
132 url = QUrl()
133 url.setScheme("file")
134 url.setPath(self.filename)
135 query = QByteArray()
136 query.append(lv).append('_').append(ver)
137 url.setEncodedQuery(query)
138 dstr += ' [<a href="%s" name="%s">%s</a>]' % (
139 url.toString(), query, self.trUtf8('diff to {0}').format(lv)
140 )
141 except IndexError:
142 pass
143 dstr += '<br />\n'
144 self.contents.insertHtml(dstr)
145
146 dstr = self.trUtf8('<i>author: {0}</i><br />\n').format(log["author"])
147 self.contents.insertHtml(dstr)
148
149 dstr = self.trUtf8('<i>date: {0}</i><br />\n')\
150 .format(formatTime(log["date"]))
151 self.contents.insertHtml(dstr)
152
153 self.contents.insertHtml('<br />\n')
154
155 for line in log["message"].splitlines():
156 self.contents.insertHtml(Utilities.html_encode(line))
157 self.contents.insertHtml('<br />\n')
158
159 if len(log['changed_paths']) > 0:
160 self.contents.insertHtml('<br />\n')
161 for changeInfo in log['changed_paths']:
162 dstr = '{0} {1}'\
163 .format(self.flags[changeInfo["action"]],
164 changeInfo["path"])
165 if changeInfo["copyfrom_path"] is not None:
166 dstr += self.trUtf8(" (copied from {0}, revision {1})")\
167 .format(changeInfo["copyfrom_path"],
168 changeInfo["copyfrom_revision"].number)
169 dstr += '<br />\n'
170 self.contents.insertHtml(dstr)
171
172 self.contents.insertHtml('<hr /><br />\n')
173 except pysvn.ClientError, e:
174 locker.unlock()
175 self.__showError(e.args[0])
176 os.chdir(cwd)
177 self.__finish()
178
179 def __finish(self):
180 """
181 Private slot called when the user pressed the button.
182 """
183 QApplication.restoreOverrideCursor()
184
185 self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
186 self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
187 self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
188
189 tc = self.contents.textCursor()
190 tc.movePosition(QTextCursor.Start)
191 self.contents.setTextCursor(tc)
192 self.contents.ensureCursorVisible()
193
194 self._cancel()
195
196 def on_buttonBox_clicked(self, button):
197 """
198 Private slot called by a button of the button box clicked.
199
200 @param button button that was clicked (QAbstractButton)
201 """
202 if button == self.buttonBox.button(QDialogButtonBox.Close):
203 self.close()
204 elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
205 self.__finish()
206
207 def __sourceChanged(self, url):
208 """
209 Private slot to handle the sourceChanged signal of the contents pane.
210
211 @param url the url that was clicked (QUrl)
212 """
213 self.contents.setSource(QUrl(''))
214 filename = url.path()
215 if Utilities.isWindowsPlatform():
216 if filename.startswith("/"):
217 filename = filename[1:]
218 ver = unicode(url.encodedQuery())
219 v1 = ver.split('_')[0]
220 v2 = ver.split('_')[1]
221 if not v1 or not v2:
222 return
223 try:
224 v1 = int(v1)
225 v2 = int(v2)
226 except ValueError:
227 return
228 self.contents.scrollToAnchor(ver)
229
230 if self.diff is None:
231 self.diff = SvnDiffDialog(self.vcs)
232 self.diff.show()
233 self.diff.start(filename, [v1, v2], pegRev = self.__pegRev)
234
235 def __showError(self, msg):
236 """
237 Private slot to show an error message.
238
239 @param msg error message to show (string or QString)
240 """
241 self.errorGroup.show()
242 self.errors.insertPlainText(msg)
243 self.errors.ensureCursorVisible()

eric ide

mercurial