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 |
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 """ |