src/eric7/Plugins/VcsPlugins/vcsPySvn/SvnLogBrowserDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
12 12
13 import pysvn 13 import pysvn
14 14
15 from PyQt6.QtCore import Qt, QDate, pyqtSlot, QPoint 15 from PyQt6.QtCore import Qt, QDate, pyqtSlot, QPoint
16 from PyQt6.QtWidgets import ( 16 from PyQt6.QtWidgets import (
17 QHeaderView, QWidget, QApplication, QDialogButtonBox, QTreeWidgetItem 17 QHeaderView,
18 QWidget,
19 QApplication,
20 QDialogButtonBox,
21 QTreeWidgetItem,
18 ) 22 )
19 23
20 from EricWidgets import EricMessageBox 24 from EricWidgets import EricMessageBox
21 from EricGui.EricOverrideCursor import EricOverrideCursor 25 from EricGui.EricOverrideCursor import EricOverrideCursor
22 26
32 36
33 class SvnLogBrowserDialog(QWidget, SvnDialogMixin, Ui_SvnLogBrowserDialog): 37 class SvnLogBrowserDialog(QWidget, SvnDialogMixin, Ui_SvnLogBrowserDialog):
34 """ 38 """
35 Class implementing a dialog to browse the log history. 39 Class implementing a dialog to browse the log history.
36 """ 40 """
41
37 def __init__(self, vcs, parent=None): 42 def __init__(self, vcs, parent=None):
38 """ 43 """
39 Constructor 44 Constructor
40 45
41 @param vcs reference to the vcs object 46 @param vcs reference to the vcs object
42 @param parent parent widget (QWidget) 47 @param parent parent widget (QWidget)
43 """ 48 """
44 super().__init__(parent) 49 super().__init__(parent)
45 self.setupUi(self) 50 self.setupUi(self)
46 SvnDialogMixin.__init__(self) 51 SvnDialogMixin.__init__(self)
47 52
48 self.__position = QPoint() 53 self.__position = QPoint()
49 54
50 self.buttonBox.button( 55 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
51 QDialogButtonBox.StandardButton.Close).setEnabled(False) 56 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
52 self.buttonBox.button( 57
53 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
54
55 self.upButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) 58 self.upButton.setIcon(UI.PixmapCache.getIcon("1uparrow"))
56 self.downButton.setIcon(UI.PixmapCache.getIcon("1downarrow")) 59 self.downButton.setIcon(UI.PixmapCache.getIcon("1downarrow"))
57 60
58 self.filesTree.headerItem().setText(self.filesTree.columnCount(), "") 61 self.filesTree.headerItem().setText(self.filesTree.columnCount(), "")
59 self.filesTree.header().setSortIndicator( 62 self.filesTree.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder)
60 0, Qt.SortOrder.AscendingOrder) 63
61
62 self.vcs = vcs 64 self.vcs = vcs
63 65
64 self.__initData() 66 self.__initData()
65 67
66 self.fromDate.setDisplayFormat("yyyy-MM-dd") 68 self.fromDate.setDisplayFormat("yyyy-MM-dd")
67 self.toDate.setDisplayFormat("yyyy-MM-dd") 69 self.toDate.setDisplayFormat("yyyy-MM-dd")
68 self.__resetUI() 70 self.__resetUI()
69 71
70 self.__messageRole = Qt.ItemDataRole.UserRole 72 self.__messageRole = Qt.ItemDataRole.UserRole
71 self.__changesRole = Qt.ItemDataRole.UserRole + 1 73 self.__changesRole = Qt.ItemDataRole.UserRole + 1
72 74
73 self.flags = { 75 self.flags = {
74 'A': self.tr('Added'), 76 "A": self.tr("Added"),
75 'D': self.tr('Deleted'), 77 "D": self.tr("Deleted"),
76 'M': self.tr('Modified'), 78 "M": self.tr("Modified"),
77 'R': self.tr('Replaced'), 79 "R": self.tr("Replaced"),
78 } 80 }
79 81
80 self.__logTreeNormalFont = self.logTree.font() 82 self.__logTreeNormalFont = self.logTree.font()
81 self.__logTreeNormalFont.setBold(False) 83 self.__logTreeNormalFont.setBold(False)
82 self.__logTreeBoldFont = self.logTree.font() 84 self.__logTreeBoldFont = self.logTree.font()
83 self.__logTreeBoldFont.setBold(True) 85 self.__logTreeBoldFont.setBold(True)
84 86
85 self.client = self.vcs.getClient() 87 self.client = self.vcs.getClient()
86 self.client.callback_cancel = self._clientCancelCallback 88 self.client.callback_cancel = self._clientCancelCallback
87 self.client.callback_get_login = self._clientLoginCallback 89 self.client.callback_get_login = self._clientLoginCallback
88 self.client.callback_ssl_server_trust_prompt = ( 90 self.client.callback_ssl_server_trust_prompt = (
89 self._clientSslServerTrustPromptCallback 91 self._clientSslServerTrustPromptCallback
90 ) 92 )
91 93
92 def __initData(self): 94 def __initData(self):
93 """ 95 """
94 Private method to (re-)initialize some data. 96 Private method to (re-)initialize some data.
95 """ 97 """
96 self.__maxDate = QDate() 98 self.__maxDate = QDate()
97 self.__minDate = QDate() 99 self.__minDate = QDate()
98 self.__filterLogsEnabled = True 100 self.__filterLogsEnabled = True
99 101
100 self.diff = None 102 self.diff = None
101 self.__lastRev = 0 103 self.__lastRev = 0
102 104
103 def closeEvent(self, e): 105 def closeEvent(self, e):
104 """ 106 """
105 Protected slot implementing a close event handler. 107 Protected slot implementing a close event handler.
106 108
107 @param e close event (QCloseEvent) 109 @param e close event (QCloseEvent)
108 """ 110 """
109 self.__position = self.pos() 111 self.__position = self.pos()
110 112
111 e.accept() 113 e.accept()
112 114
113 def show(self): 115 def show(self):
114 """ 116 """
115 Public slot to show the dialog. 117 Public slot to show the dialog.
116 """ 118 """
117 if not self.__position.isNull(): 119 if not self.__position.isNull():
118 self.move(self.__position) 120 self.move(self.__position)
119 self.__resetUI() 121 self.__resetUI()
120 122
121 super().show() 123 super().show()
122 124
123 def __resetUI(self): 125 def __resetUI(self):
124 """ 126 """
125 Private method to reset the user interface. 127 Private method to reset the user interface.
126 """ 128 """
127 self.fromDate.setDate(QDate.currentDate()) 129 self.fromDate.setDate(QDate.currentDate())
128 self.toDate.setDate(QDate.currentDate()) 130 self.toDate.setDate(QDate.currentDate())
129 self.fieldCombo.setCurrentIndex(self.fieldCombo.findText( 131 self.fieldCombo.setCurrentIndex(self.fieldCombo.findText(self.tr("Message")))
130 self.tr("Message"))) 132 self.limitSpinBox.setValue(self.vcs.getPlugin().getPreferences("LogLimit"))
131 self.limitSpinBox.setValue(self.vcs.getPlugin().getPreferences( 133 self.stopCheckBox.setChecked(
132 "LogLimit")) 134 self.vcs.getPlugin().getPreferences("StopLogOnCopy")
133 self.stopCheckBox.setChecked(self.vcs.getPlugin().getPreferences( 135 )
134 "StopLogOnCopy")) 136
135
136 self.logTree.clear() 137 self.logTree.clear()
137 138
138 self.nextButton.setEnabled(True) 139 self.nextButton.setEnabled(True)
139 self.limitSpinBox.setEnabled(True) 140 self.limitSpinBox.setEnabled(True)
140 141
141 def _reset(self): 142 def _reset(self):
142 """ 143 """
143 Protected method to reset the internal state of the dialog. 144 Protected method to reset the internal state of the dialog.
144 """ 145 """
145 SvnDialogMixin._reset(self) 146 SvnDialogMixin._reset(self)
146 147
147 self.cancelled = False 148 self.cancelled = False
148 149
149 self.buttonBox.button( 150 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
150 QDialogButtonBox.StandardButton.Close).setEnabled(False) 151 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
151 self.buttonBox.button( 152 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
152 QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
153 self.buttonBox.button(
154 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
155 QApplication.processEvents() 153 QApplication.processEvents()
156 154
157 def __resizeColumnsLog(self): 155 def __resizeColumnsLog(self):
158 """ 156 """
159 Private method to resize the log tree columns. 157 Private method to resize the log tree columns.
160 """ 158 """
161 self.logTree.header().resizeSections( 159 self.logTree.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
162 QHeaderView.ResizeMode.ResizeToContents)
163 self.logTree.header().setStretchLastSection(True) 160 self.logTree.header().setStretchLastSection(True)
164 161
165 def __resortLog(self): 162 def __resortLog(self):
166 """ 163 """
167 Private method to resort the log tree. 164 Private method to resort the log tree.
168 """ 165 """
169 self.logTree.sortItems( 166 self.logTree.sortItems(
170 self.logTree.sortColumn(), 167 self.logTree.sortColumn(), self.logTree.header().sortIndicatorOrder()
171 self.logTree.header().sortIndicatorOrder()) 168 )
172 169
173 def __resizeColumnsFiles(self): 170 def __resizeColumnsFiles(self):
174 """ 171 """
175 Private method to resize the changed files tree columns. 172 Private method to resize the changed files tree columns.
176 """ 173 """
177 self.filesTree.header().resizeSections( 174 self.filesTree.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
178 QHeaderView.ResizeMode.ResizeToContents)
179 self.filesTree.header().setStretchLastSection(True) 175 self.filesTree.header().setStretchLastSection(True)
180 176
181 def __resortFiles(self): 177 def __resortFiles(self):
182 """ 178 """
183 Private method to resort the changed files tree. 179 Private method to resort the changed files tree.
184 """ 180 """
185 sortColumn = self.filesTree.sortColumn() 181 sortColumn = self.filesTree.sortColumn()
182 self.filesTree.sortItems(1, self.filesTree.header().sortIndicatorOrder())
186 self.filesTree.sortItems( 183 self.filesTree.sortItems(
187 1, self.filesTree.header().sortIndicatorOrder()) 184 sortColumn, self.filesTree.header().sortIndicatorOrder()
188 self.filesTree.sortItems( 185 )
189 sortColumn, self.filesTree.header().sortIndicatorOrder()) 186
190
191 def __generateLogItem(self, author, date, message, revision, changedPaths): 187 def __generateLogItem(self, author, date, message, revision, changedPaths):
192 """ 188 """
193 Private method to generate a log tree entry. 189 Private method to generate a log tree entry.
194 190
195 @param author author info (string) 191 @param author author info (string)
196 @param date date info (integer) 192 @param date date info (integer)
197 @param message text of the log message (string) 193 @param message text of the log message (string)
198 @param revision revision info (string or pysvn.opt_revision_kind) 194 @param revision revision info (string or pysvn.opt_revision_kind)
199 @param changedPaths list of pysvn dictionary like objects containing 195 @param changedPaths list of pysvn dictionary like objects containing
205 self.__lastRev = 0 201 self.__lastRev = 0
206 else: 202 else:
207 rev = revision.number 203 rev = revision.number
208 self.__lastRev = revision.number 204 self.__lastRev = revision.number
209 dt = formatTime(date) if date else "" 205 dt = formatTime(date) if date else ""
210 206
211 itm = QTreeWidgetItem(self.logTree) 207 itm = QTreeWidgetItem(self.logTree)
212 itm.setData(0, Qt.ItemDataRole.DisplayRole, rev) 208 itm.setData(0, Qt.ItemDataRole.DisplayRole, rev)
213 itm.setData(1, Qt.ItemDataRole.DisplayRole, author) 209 itm.setData(1, Qt.ItemDataRole.DisplayRole, author)
214 itm.setData(2, Qt.ItemDataRole.DisplayRole, dt) 210 itm.setData(2, Qt.ItemDataRole.DisplayRole, dt)
215 itm.setData(3, Qt.ItemDataRole.DisplayRole, 211 itm.setData(3, Qt.ItemDataRole.DisplayRole, " ".join(message.splitlines()))
216 " ".join(message.splitlines())) 212
217
218 changes = [] 213 changes = []
219 for changedPath in changedPaths: 214 for changedPath in changedPaths:
220 copyPath = ( 215 copyPath = (
221 "" 216 ""
222 if changedPath["copyfrom_path"] is None else 217 if changedPath["copyfrom_path"] is None
223 changedPath["copyfrom_path"] 218 else changedPath["copyfrom_path"]
224 ) 219 )
225 copyRev = ( 220 copyRev = (
226 "" 221 ""
227 if changedPath["copyfrom_revision"] is None else 222 if changedPath["copyfrom_revision"] is None
228 "{0:7d}".format(changedPath["copyfrom_revision"].number) 223 else "{0:7d}".format(changedPath["copyfrom_revision"].number)
229 ) 224 )
230 change = { 225 change = {
231 "action": changedPath["action"], 226 "action": changedPath["action"],
232 "path": changedPath["path"], 227 "path": changedPath["path"],
233 "copyfrom_path": copyPath, 228 "copyfrom_path": copyPath,
234 "copyfrom_revision": copyRev, 229 "copyfrom_revision": copyRev,
235 } 230 }
236 changes.append(change) 231 changes.append(change)
237 itm.setData(0, self.__messageRole, message) 232 itm.setData(0, self.__messageRole, message)
238 itm.setData(0, self.__changesRole, changes) 233 itm.setData(0, self.__changesRole, changes)
239 234
240 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignRight) 235 itm.setTextAlignment(0, Qt.AlignmentFlag.AlignRight)
241 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignLeft) 236 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignLeft)
242 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignLeft) 237 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignLeft)
243 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignLeft) 238 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignLeft)
244 itm.setTextAlignment(4, Qt.AlignmentFlag.AlignLeft) 239 itm.setTextAlignment(4, Qt.AlignmentFlag.AlignLeft)
245 240
246 return itm 241 return itm
247 242
248 def __generateFileItem(self, action, path, copyFrom, copyRev): 243 def __generateFileItem(self, action, path, copyFrom, copyRev):
249 """ 244 """
250 Private method to generate a changed files tree entry. 245 Private method to generate a changed files tree entry.
251 246
252 @param action indicator for the change action ("A", "D" or "M") 247 @param action indicator for the change action ("A", "D" or "M")
253 @param path path of the file in the repository (string) 248 @param path path of the file in the repository (string)
254 @param copyFrom path the file was copied from (None, string) 249 @param copyFrom path the file was copied from (None, string)
255 @param copyRev revision the file was copied from (None, string) 250 @param copyRev revision the file was copied from (None, string)
256 @return reference to the generated item (QTreeWidgetItem) 251 @return reference to the generated item (QTreeWidgetItem)
257 """ 252 """
258 itm = QTreeWidgetItem( 253 itm = QTreeWidgetItem(
259 self.filesTree, 254 self.filesTree, [self.flags[action], path, copyFrom, copyRev]
260 [self.flags[action], path, copyFrom, copyRev] 255 )
261 ) 256
262
263 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignRight) 257 itm.setTextAlignment(3, Qt.AlignmentFlag.AlignRight)
264 258
265 return itm 259 return itm
266 260
267 def __getLogEntries(self, startRev=None): 261 def __getLogEntries(self, startRev=None):
268 """ 262 """
269 Private method to retrieve log entries from the repository. 263 Private method to retrieve log entries from the repository.
270 264
271 @param startRev revision number to start from (integer, string) 265 @param startRev revision number to start from (integer, string)
272 """ 266 """
273 fetchLimit = 10 267 fetchLimit = 10
274 self._reset() 268 self._reset()
275 269
276 limit = self.limitSpinBox.value() 270 limit = self.limitSpinBox.value()
277 if startRev is None: 271 if startRev is None:
278 start = pysvn.Revision(pysvn.opt_revision_kind.head) 272 start = pysvn.Revision(pysvn.opt_revision_kind.head)
279 else: 273 else:
280 try: 274 try:
281 start = pysvn.Revision(pysvn.opt_revision_kind.number, 275 start = pysvn.Revision(pysvn.opt_revision_kind.number, int(startRev))
282 int(startRev))
283 except TypeError: 276 except TypeError:
284 start = pysvn.Revision(pysvn.opt_revision_kind.head) 277 start = pysvn.Revision(pysvn.opt_revision_kind.head)
285 278
286 with EricOverrideCursor(): 279 with EricOverrideCursor():
287 cwd = os.getcwd() 280 cwd = os.getcwd()
288 os.chdir(self.dname) 281 os.chdir(self.dname)
289 try: 282 try:
290 nextRev = 0 283 nextRev = 0
293 with EricMutexLocker(self.vcs.vcsExecutionMutex): 286 with EricMutexLocker(self.vcs.vcsExecutionMutex):
294 while fetched < limit: 287 while fetched < limit:
295 flimit = min(fetchLimit, limit - fetched) 288 flimit = min(fetchLimit, limit - fetched)
296 revstart = ( 289 revstart = (
297 start 290 start
298 if fetched == 0 else 291 if fetched == 0
299 pysvn.Revision(pysvn.opt_revision_kind.number, 292 else pysvn.Revision(pysvn.opt_revision_kind.number, nextRev)
300 nextRev)
301 ) 293 )
302 allLogs = self.client.log( 294 allLogs = self.client.log(
303 self.fname, revision_start=revstart, 295 self.fname,
304 discover_changed_paths=True, limit=flimit + 1, 296 revision_start=revstart,
305 strict_node_history=self.stopCheckBox.isChecked()) 297 discover_changed_paths=True,
306 if ( 298 limit=flimit + 1,
307 len(allLogs) <= flimit or 299 strict_node_history=self.stopCheckBox.isChecked(),
308 self._clientCancelCallback() 300 )
309 ): 301 if len(allLogs) <= flimit or self._clientCancelCallback():
310 logs.extend(allLogs) 302 logs.extend(allLogs)
311 break 303 break
312 else: 304 else:
313 logs.extend(allLogs[:-1]) 305 logs.extend(allLogs[:-1])
314 nextRev = allLogs[-1]["revision"].number 306 nextRev = allLogs[-1]["revision"].number
315 fetched += fetchLimit 307 fetched += fetchLimit
316 308
317 for log in logs: 309 for log in logs:
318 author = log["author"] 310 author = log["author"]
319 message = log["message"] 311 message = log["message"]
320 self.__generateLogItem( 312 self.__generateLogItem(
321 author, log["date"], message, 313 author,
322 log["revision"], log['changed_paths']) 314 log["date"],
315 message,
316 log["revision"],
317 log["changed_paths"],
318 )
323 dt = dateFromTime_t(log["date"]) 319 dt = dateFromTime_t(log["date"])
324 if ( 320 if not self.__maxDate.isValid() and not self.__minDate.isValid():
325 not self.__maxDate.isValid() and
326 not self.__minDate.isValid()
327 ):
328 self.__maxDate = dt 321 self.__maxDate = dt
329 self.__minDate = dt 322 self.__minDate = dt
330 else: 323 else:
331 if self.__maxDate < dt: 324 if self.__maxDate < dt:
332 self.__maxDate = dt 325 self.__maxDate = dt
341 self.fromDate.setDate(self.__minDate) 334 self.fromDate.setDate(self.__minDate)
342 self.toDate.setMinimumDate(self.__minDate) 335 self.toDate.setMinimumDate(self.__minDate)
343 self.toDate.setMaximumDate(self.__maxDate) 336 self.toDate.setMaximumDate(self.__maxDate)
344 self.toDate.setDate(self.__maxDate) 337 self.toDate.setDate(self.__maxDate)
345 self.__filterLogsEnabled = True 338 self.__filterLogsEnabled = True
346 339
347 self.__resizeColumnsLog() 340 self.__resizeColumnsLog()
348 self.__resortLog() 341 self.__resortLog()
349 self.__filterLogs() 342 self.__filterLogs()
350 except pysvn.ClientError as e: 343 except pysvn.ClientError as e:
351 self.__showError(e.args[0]) 344 self.__showError(e.args[0])
352 os.chdir(cwd) 345 os.chdir(cwd)
353 self.__finish() 346 self.__finish()
354 347
355 def start(self, fn, isFile=False): 348 def start(self, fn, isFile=False):
356 """ 349 """
357 Public slot to start the svn log command. 350 Public slot to start the svn log command.
358 351
359 @param fn filename to show the log for (string) 352 @param fn filename to show the log for (string)
360 @param isFile flag indicating log for a file is to be shown 353 @param isFile flag indicating log for a file is to be shown
361 (boolean) 354 (boolean)
362 """ 355 """
363 self.sbsCheckBox.setEnabled(isFile) 356 self.sbsCheckBox.setEnabled(isFile)
364 self.sbsCheckBox.setVisible(isFile) 357 self.sbsCheckBox.setVisible(isFile)
365 358
366 self.__initData() 359 self.__initData()
367 360
368 self.filename = fn 361 self.filename = fn
369 self.dname, self.fname = self.vcs.splitPath(fn) 362 self.dname, self.fname = self.vcs.splitPath(fn)
370 363
371 self.activateWindow() 364 self.activateWindow()
372 self.raise_() 365 self.raise_()
373 366
374 self.logTree.clear() 367 self.logTree.clear()
375 self.__getLogEntries() 368 self.__getLogEntries()
376 self.logTree.setCurrentItem(self.logTree.topLevelItem(0)) 369 self.logTree.setCurrentItem(self.logTree.topLevelItem(0))
377 370
378 def __finish(self): 371 def __finish(self):
379 """ 372 """
380 Private slot called when the user pressed the button. 373 Private slot called when the user pressed the button.
381 """ 374 """
382 self.buttonBox.button( 375 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
383 QDialogButtonBox.StandardButton.Close).setEnabled(True) 376 self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
384 self.buttonBox.button( 377 self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
385 QDialogButtonBox.StandardButton.Cancel).setEnabled(False) 378
386 self.buttonBox.button(
387 QDialogButtonBox.StandardButton.Close).setDefault(True)
388
389 self._cancel() 379 self._cancel()
390 380
391 def __diffRevisions(self, rev1, rev2, peg_rev): 381 def __diffRevisions(self, rev1, rev2, peg_rev):
392 """ 382 """
393 Private method to do a diff of two revisions. 383 Private method to do a diff of two revisions.
394 384
395 @param rev1 first revision number (integer) 385 @param rev1 first revision number (integer)
396 @param rev2 second revision number (integer) 386 @param rev2 second revision number (integer)
397 @param peg_rev revision number to use as a reference (integer) 387 @param peg_rev revision number to use as a reference (integer)
398 """ 388 """
399 if self.sbsCheckBox.isEnabled() and self.sbsCheckBox.isChecked(): 389 if self.sbsCheckBox.isEnabled() and self.sbsCheckBox.isChecked():
400 self.vcs.vcsSbsDiff(self.filename, 390 self.vcs.vcsSbsDiff(self.filename, revisions=(str(rev1), str(rev2)))
401 revisions=(str(rev1), str(rev2)))
402 else: 391 else:
403 if self.diff is None: 392 if self.diff is None:
404 from .SvnDiffDialog import SvnDiffDialog 393 from .SvnDiffDialog import SvnDiffDialog
394
405 self.diff = SvnDiffDialog(self.vcs) 395 self.diff = SvnDiffDialog(self.vcs)
406 self.diff.show() 396 self.diff.show()
407 self.diff.raise_() 397 self.diff.raise_()
408 QApplication.processEvents() 398 QApplication.processEvents()
409 self.diff.start(self.filename, [rev1, rev2], pegRev=peg_rev) 399 self.diff.start(self.filename, [rev1, rev2], pegRev=peg_rev)
410 400
411 def on_buttonBox_clicked(self, button): 401 def on_buttonBox_clicked(self, button):
412 """ 402 """
413 Private slot called by a button of the button box clicked. 403 Private slot called by a button of the button box clicked.
414 404
415 @param button button that was clicked (QAbstractButton) 405 @param button button that was clicked (QAbstractButton)
416 """ 406 """
417 if button == self.buttonBox.button( 407 if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
418 QDialogButtonBox.StandardButton.Close
419 ):
420 self.close() 408 self.close()
421 elif button == self.buttonBox.button( 409 elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
422 QDialogButtonBox.StandardButton.Cancel
423 ):
424 self.cancelled = True 410 self.cancelled = True
425 self.__finish() 411 self.__finish()
426 412
427 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem) 413 @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
428 def on_logTree_currentItemChanged(self, current, previous): 414 def on_logTree_currentItemChanged(self, current, previous):
429 """ 415 """
430 Private slot called, when the current item of the log tree changes. 416 Private slot called, when the current item of the log tree changes.
431 417
432 @param current reference to the new current item (QTreeWidgetItem) 418 @param current reference to the new current item (QTreeWidgetItem)
433 @param previous reference to the old current item (QTreeWidgetItem) 419 @param previous reference to the old current item (QTreeWidgetItem)
434 """ 420 """
435 if current is not None: 421 if current is not None:
436 self.messageEdit.setPlainText(current.data(0, self.__messageRole)) 422 self.messageEdit.setPlainText(current.data(0, self.__messageRole))
437 423
438 self.filesTree.clear() 424 self.filesTree.clear()
439 changes = current.data(0, self.__changesRole) 425 changes = current.data(0, self.__changesRole)
440 if len(changes) > 0: 426 if len(changes) > 0:
441 for change in changes: 427 for change in changes:
442 self.__generateFileItem( 428 self.__generateFileItem(
443 change["action"], change["path"], 429 change["action"],
444 change["copyfrom_path"], change["copyfrom_revision"]) 430 change["path"],
431 change["copyfrom_path"],
432 change["copyfrom_revision"],
433 )
445 self.__resizeColumnsFiles() 434 self.__resizeColumnsFiles()
446 self.__resortFiles() 435 self.__resortFiles()
447 436
448 self.diffPreviousButton.setEnabled( 437 self.diffPreviousButton.setEnabled(
449 current != self.logTree.topLevelItem( 438 current != self.logTree.topLevelItem(self.logTree.topLevelItemCount() - 1)
450 self.logTree.topLevelItemCount() - 1)) 439 )
451 440
452 # Highlight the current entry using a bold font 441 # Highlight the current entry using a bold font
453 for col in range(self.logTree.columnCount()): 442 for col in range(self.logTree.columnCount()):
454 current and current.setFont(col, self.__logTreeBoldFont) 443 current and current.setFont(col, self.__logTreeBoldFont)
455 previous and previous.setFont(col, self.__logTreeNormalFont) 444 previous and previous.setFont(col, self.__logTreeNormalFont)
456 445
457 # set the state of the up and down buttons 446 # set the state of the up and down buttons
458 self.upButton.setEnabled( 447 self.upButton.setEnabled(
459 current is not None and 448 current is not None and self.logTree.indexOfTopLevelItem(current) > 0
460 self.logTree.indexOfTopLevelItem(current) > 0) 449 )
461 self.downButton.setEnabled( 450 self.downButton.setEnabled(current is not None and int(current.text(0)) > 1)
462 current is not None and 451
463 int(current.text(0)) > 1)
464
465 @pyqtSlot() 452 @pyqtSlot()
466 def on_logTree_itemSelectionChanged(self): 453 def on_logTree_itemSelectionChanged(self):
467 """ 454 """
468 Private slot called, when the selection has changed. 455 Private slot called, when the selection has changed.
469 """ 456 """
470 self.diffRevisionsButton.setEnabled( 457 self.diffRevisionsButton.setEnabled(len(self.logTree.selectedItems()) == 2)
471 len(self.logTree.selectedItems()) == 2) 458
472
473 @pyqtSlot() 459 @pyqtSlot()
474 def on_nextButton_clicked(self): 460 def on_nextButton_clicked(self):
475 """ 461 """
476 Private slot to handle the Next button. 462 Private slot to handle the Next button.
477 """ 463 """
478 if self.__lastRev > 1: 464 if self.__lastRev > 1:
479 self.__getLogEntries(self.__lastRev - 1) 465 self.__getLogEntries(self.__lastRev - 1)
480 466
481 @pyqtSlot() 467 @pyqtSlot()
482 def on_diffPreviousButton_clicked(self): 468 def on_diffPreviousButton_clicked(self):
483 """ 469 """
484 Private slot to handle the Diff to Previous button. 470 Private slot to handle the Diff to Previous button.
485 """ 471 """
486 itm = self.logTree.topLevelItem(0) 472 itm = self.logTree.topLevelItem(0)
487 if itm is None: 473 if itm is None:
488 self.diffPreviousButton.setEnabled(False) 474 self.diffPreviousButton.setEnabled(False)
489 return 475 return
490 peg_rev = int(itm.text(0)) 476 peg_rev = int(itm.text(0))
491 477
492 itm = self.logTree.currentItem() 478 itm = self.logTree.currentItem()
493 if itm is None: 479 if itm is None:
494 self.diffPreviousButton.setEnabled(False) 480 self.diffPreviousButton.setEnabled(False)
495 return 481 return
496 rev2 = int(itm.text(0)) 482 rev2 = int(itm.text(0))
497 483
498 itm = self.logTree.topLevelItem( 484 itm = self.logTree.topLevelItem(self.logTree.indexOfTopLevelItem(itm) + 1)
499 self.logTree.indexOfTopLevelItem(itm) + 1)
500 if itm is None: 485 if itm is None:
501 self.diffPreviousButton.setEnabled(False) 486 self.diffPreviousButton.setEnabled(False)
502 return 487 return
503 rev1 = int(itm.text(0)) 488 rev1 = int(itm.text(0))
504 489
505 self.__diffRevisions(rev1, rev2, peg_rev) 490 self.__diffRevisions(rev1, rev2, peg_rev)
506 491
507 @pyqtSlot() 492 @pyqtSlot()
508 def on_diffRevisionsButton_clicked(self): 493 def on_diffRevisionsButton_clicked(self):
509 """ 494 """
510 Private slot to handle the Compare Revisions button. 495 Private slot to handle the Compare Revisions button.
511 """ 496 """
512 items = self.logTree.selectedItems() 497 items = self.logTree.selectedItems()
513 if len(items) != 2: 498 if len(items) != 2:
514 self.diffRevisionsButton.setEnabled(False) 499 self.diffRevisionsButton.setEnabled(False)
515 return 500 return
516 501
517 rev2 = int(items[0].text(0)) 502 rev2 = int(items[0].text(0))
518 rev1 = int(items[1].text(0)) 503 rev1 = int(items[1].text(0))
519 504
520 itm = self.logTree.topLevelItem(0) 505 itm = self.logTree.topLevelItem(0)
521 if itm is None: 506 if itm is None:
522 self.diffPreviousButton.setEnabled(False) 507 self.diffPreviousButton.setEnabled(False)
523 return 508 return
524 peg_rev = int(itm.text(0)) 509 peg_rev = int(itm.text(0))
525 510
526 self.__diffRevisions(min(rev1, rev2), max(rev1, rev2), peg_rev) 511 self.__diffRevisions(min(rev1, rev2), max(rev1, rev2), peg_rev)
527 512
528 def __showError(self, msg): 513 def __showError(self, msg):
529 """ 514 """
530 Private slot to show an error message. 515 Private slot to show an error message.
531 516
532 @param msg error message to show (string) 517 @param msg error message to show (string)
533 """ 518 """
534 EricMessageBox.critical( 519 EricMessageBox.critical(self, self.tr("Subversion Error"), msg)
535 self, 520
536 self.tr("Subversion Error"),
537 msg)
538
539 @pyqtSlot(QDate) 521 @pyqtSlot(QDate)
540 def on_fromDate_dateChanged(self, date): 522 def on_fromDate_dateChanged(self, date):
541 """ 523 """
542 Private slot called, when the from date changes. 524 Private slot called, when the from date changes.
543 525
544 @param date new date (QDate) 526 @param date new date (QDate)
545 """ 527 """
546 self.__filterLogs() 528 self.__filterLogs()
547 529
548 @pyqtSlot(QDate) 530 @pyqtSlot(QDate)
549 def on_toDate_dateChanged(self, date): 531 def on_toDate_dateChanged(self, date):
550 """ 532 """
551 Private slot called, when the from date changes. 533 Private slot called, when the from date changes.
552 534
553 @param date new date (QDate) 535 @param date new date (QDate)
554 """ 536 """
555 self.__filterLogs() 537 self.__filterLogs()
556 538
557 @pyqtSlot(int) 539 @pyqtSlot(int)
558 def on_fieldCombo_activated(self, index): 540 def on_fieldCombo_activated(self, index):
559 """ 541 """
560 Private slot called, when a new filter field is selected. 542 Private slot called, when a new filter field is selected.
561 543
562 @param index index of the selected entry 544 @param index index of the selected entry
563 @type int 545 @type int
564 """ 546 """
565 self.__filterLogs() 547 self.__filterLogs()
566 548
567 @pyqtSlot(str) 549 @pyqtSlot(str)
568 def on_rxEdit_textChanged(self, txt): 550 def on_rxEdit_textChanged(self, txt):
569 """ 551 """
570 Private slot called, when a filter expression is entered. 552 Private slot called, when a filter expression is entered.
571 553
572 @param txt filter expression (string) 554 @param txt filter expression (string)
573 """ 555 """
574 self.__filterLogs() 556 self.__filterLogs()
575 557
576 def __filterLogs(self): 558 def __filterLogs(self):
577 """ 559 """
578 Private method to filter the log entries. 560 Private method to filter the log entries.
579 """ 561 """
580 if self.__filterLogsEnabled: 562 if self.__filterLogsEnabled:
586 searchRx = re.compile(self.rxEdit.text(), re.IGNORECASE) 568 searchRx = re.compile(self.rxEdit.text(), re.IGNORECASE)
587 elif txt == self.tr("Revision"): 569 elif txt == self.tr("Revision"):
588 fieldIndex = 0 570 fieldIndex = 0
589 txt = self.rxEdit.text() 571 txt = self.rxEdit.text()
590 if txt.startswith("^"): 572 if txt.startswith("^"):
591 searchRx = re.compile( 573 searchRx = re.compile(r"^\s*{0}".format(txt[1:]), re.IGNORECASE)
592 r"^\s*{0}".format(txt[1:]), re.IGNORECASE)
593 else: 574 else:
594 searchRx = re.compile(txt, re.IGNORECASE) 575 searchRx = re.compile(txt, re.IGNORECASE)
595 else: 576 else:
596 fieldIndex = 3 577 fieldIndex = 3
597 searchRx = re.compile(self.rxEdit.text(), re.IGNORECASE) 578 searchRx = re.compile(self.rxEdit.text(), re.IGNORECASE)
598 579
599 currentItem = self.logTree.currentItem() 580 currentItem = self.logTree.currentItem()
600 for topIndex in range(self.logTree.topLevelItemCount()): 581 for topIndex in range(self.logTree.topLevelItemCount()):
601 topItem = self.logTree.topLevelItem(topIndex) 582 topItem = self.logTree.topLevelItem(topIndex)
602 if ( 583 if (
603 topItem.text(2) <= to_ and 584 topItem.text(2) <= to_
604 topItem.text(2) >= from_ and 585 and topItem.text(2) >= from_
605 searchRx.search(topItem.text(fieldIndex)) is not None 586 and searchRx.search(topItem.text(fieldIndex)) is not None
606 ): 587 ):
607 topItem.setHidden(False) 588 topItem.setHidden(False)
608 if topItem is currentItem: 589 if topItem is currentItem:
609 self.on_logTree_currentItemChanged(topItem, None) 590 self.on_logTree_currentItemChanged(topItem, None)
610 else: 591 else:
611 topItem.setHidden(True) 592 topItem.setHidden(True)
612 if topItem is currentItem: 593 if topItem is currentItem:
613 self.messageEdit.clear() 594 self.messageEdit.clear()
614 self.filesTree.clear() 595 self.filesTree.clear()
615 596
616 @pyqtSlot(bool) 597 @pyqtSlot(bool)
617 def on_stopCheckBox_clicked(self, checked): 598 def on_stopCheckBox_clicked(self, checked):
618 """ 599 """
619 Private slot called, when the stop on copy/move checkbox is clicked. 600 Private slot called, when the stop on copy/move checkbox is clicked.
620 601
621 @param checked flag indicating the check box state (boolean) 602 @param checked flag indicating the check box state (boolean)
622 """ 603 """
623 self.vcs.getPlugin().setPreferences("StopLogOnCopy", 604 self.vcs.getPlugin().setPreferences(
624 int(self.stopCheckBox.isChecked())) 605 "StopLogOnCopy", int(self.stopCheckBox.isChecked())
606 )
625 self.nextButton.setEnabled(True) 607 self.nextButton.setEnabled(True)
626 self.limitSpinBox.setEnabled(True) 608 self.limitSpinBox.setEnabled(True)
627 609
628 @pyqtSlot() 610 @pyqtSlot()
629 def on_upButton_clicked(self): 611 def on_upButton_clicked(self):
630 """ 612 """
631 Private slot to move the current item up one entry. 613 Private slot to move the current item up one entry.
632 """ 614 """
633 itm = self.logTree.itemAbove(self.logTree.currentItem()) 615 itm = self.logTree.itemAbove(self.logTree.currentItem())
634 if itm: 616 if itm:
635 self.logTree.setCurrentItem(itm) 617 self.logTree.setCurrentItem(itm)
636 618
637 @pyqtSlot() 619 @pyqtSlot()
638 def on_downButton_clicked(self): 620 def on_downButton_clicked(self):
639 """ 621 """
640 Private slot to move the current item down one entry. 622 Private slot to move the current item down one entry.
641 """ 623 """

eric ide

mercurial