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