eric7/Plugins/VcsPlugins/vcsMercurial/HgStatusDialog.py

branch
eric7
changeset 8312
800c432b34c8
parent 8259
2bbec88047dd
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2010 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a dialog to show the output of the hg status command
8 process.
9 """
10
11 import os
12
13 from PyQt5.QtCore import pyqtSlot, Qt, QSize
14 from PyQt5.QtGui import QTextCursor
15 from PyQt5.QtWidgets import (
16 QWidget, QDialogButtonBox, QMenu, QHeaderView, QTreeWidgetItem
17 )
18
19 from E5Gui.E5Application import e5App
20 from E5Gui import E5MessageBox
21
22 from .Ui_HgStatusDialog import Ui_HgStatusDialog
23
24 from .HgDiffHighlighter import HgDiffHighlighter
25 from .HgDiffGenerator import HgDiffGenerator
26
27 import Preferences
28 import UI.PixmapCache
29
30
31 class HgStatusDialog(QWidget, Ui_HgStatusDialog):
32 """
33 Class implementing a dialog to show the output of the hg status command
34 process.
35 """
36 def __init__(self, vcs, mq=False, parent=None):
37 """
38 Constructor
39
40 @param vcs reference to the vcs object
41 @param mq flag indicating to show a queue repo status (boolean)
42 @param parent parent widget (QWidget)
43 """
44 super().__init__(parent)
45 self.setupUi(self)
46
47 self.__toBeCommittedColumn = 0
48 self.__statusColumn = 1
49 self.__pathColumn = 2
50 self.__lastColumn = self.statusList.columnCount()
51
52 self.refreshButton = self.buttonBox.addButton(
53 self.tr("Refresh"), QDialogButtonBox.ButtonRole.ActionRole)
54 self.refreshButton.setToolTip(
55 self.tr("Press to refresh the status display"))
56 self.refreshButton.setEnabled(False)
57 self.buttonBox.button(
58 QDialogButtonBox.StandardButton.Close).setEnabled(False)
59 self.buttonBox.button(
60 QDialogButtonBox.StandardButton.Cancel).setDefault(True)
61
62 self.diff = None
63 self.vcs = vcs
64 self.vcs.committed.connect(self.__committed)
65 self.__hgClient = self.vcs.getClient()
66 self.__mq = mq
67
68 self.statusList.headerItem().setText(self.__lastColumn, "")
69 self.statusList.header().setSortIndicator(
70 self.__pathColumn, Qt.SortOrder.AscendingOrder)
71
72 font = Preferences.getEditorOtherFonts("MonospacedFont")
73 self.diffEdit.document().setDefaultFont(font)
74
75 self.diffHighlighter = HgDiffHighlighter(self.diffEdit.document())
76 self.__diffGenerator = HgDiffGenerator(vcs, self)
77 self.__diffGenerator.finished.connect(self.__generatorFinished)
78
79 self.__selectedName = ""
80
81 self.modifiedIndicators = [
82 self.tr('added'),
83 self.tr('modified'),
84 self.tr('removed'),
85 ]
86
87 self.unversionedIndicators = [
88 self.tr('not tracked'),
89 ]
90
91 self.missingIndicators = [
92 self.tr('missing')
93 ]
94
95 self.status = {
96 'A': self.tr('added'),
97 'C': self.tr('normal'),
98 'I': self.tr('ignored'),
99 'M': self.tr('modified'),
100 'R': self.tr('removed'),
101 '?': self.tr('not tracked'),
102 '!': self.tr('missing'),
103 }
104
105 self.__initActionsMenu()
106
107 if mq:
108 self.diffLabel.setVisible(False)
109 self.diffEdit.setVisible(False)
110 self.actionsButton.setEnabled(False)
111 self.diffSplitter.setSizes([600, 0])
112 else:
113 self.diffSplitter.setSizes([300, 300])
114
115 def __initActionsMenu(self):
116 """
117 Private method to initialize the actions menu.
118 """
119 self.__actionsMenu = QMenu()
120 self.__actionsMenu.setTearOffEnabled(True)
121 self.__actionsMenu.setToolTipsVisible(True)
122 self.__actionsMenu.aboutToShow.connect(self.__showActionsMenu)
123
124 self.__commitAct = self.__actionsMenu.addAction(
125 self.tr("Commit"), self.__commit)
126 self.__commitAct.setToolTip(self.tr("Commit the selected changes"))
127 self.__commitSelectAct = self.__actionsMenu.addAction(
128 self.tr("Select all for commit"), self.__commitSelectAll)
129 self.__commitDeselectAct = self.__actionsMenu.addAction(
130 self.tr("Unselect all from commit"), self.__commitDeselectAll)
131
132 self.__actionsMenu.addSeparator()
133
134 self.__addAct = self.__actionsMenu.addAction(
135 self.tr("Add"), self.__add)
136 self.__addAct.setToolTip(self.tr("Add the selected files"))
137 self.__lfAddLargeAct = self.__actionsMenu.addAction(
138 self.tr("Add as Large Files"), lambda: self.__lfAdd("large"))
139 self.__lfAddLargeAct.setToolTip(self.tr(
140 "Add the selected files as a large files using the 'Large Files'"
141 " extension"))
142 self.__lfAddNormalAct = self.__actionsMenu.addAction(
143 self.tr("Add as Normal Files"), lambda: self.__lfAdd("normal"))
144 self.__lfAddNormalAct.setToolTip(self.tr(
145 "Add the selected files as a normal files using the 'Large Files'"
146 " extension"))
147
148 self.__actionsMenu.addSeparator()
149
150 self.__diffAct = self.__actionsMenu.addAction(
151 self.tr("Differences"), self.__diff)
152 self.__diffAct.setToolTip(self.tr(
153 "Shows the differences of the selected entry in a"
154 " separate dialog"))
155 self.__sbsDiffAct = self.__actionsMenu.addAction(
156 self.tr("Differences Side-By-Side"), self.__sbsDiff)
157 self.__sbsDiffAct.setToolTip(self.tr(
158 "Shows the differences of the selected entry side-by-side in"
159 " a separate dialog"))
160
161 self.__actionsMenu.addSeparator()
162
163 self.__revertAct = self.__actionsMenu.addAction(
164 self.tr("Revert"), self.__revert)
165 self.__revertAct.setToolTip(self.tr(
166 "Reverts the changes of the selected files"))
167
168 self.__actionsMenu.addSeparator()
169
170 self.__forgetAct = self.__actionsMenu.addAction(
171 self.tr("Forget missing"), self.__forget)
172 self.__forgetAct.setToolTip(self.tr(
173 "Forgets about the selected missing files"))
174 self.__restoreAct = self.__actionsMenu.addAction(
175 self.tr("Restore missing"), self.__restoreMissing)
176 self.__restoreAct.setToolTip(self.tr(
177 "Restores the selected missing files"))
178
179 self.__actionsMenu.addSeparator()
180
181 self.__commitMergeAct = self.__actionsMenu.addAction(
182 self.tr("Commit Merge"), self.__commitMerge)
183 self.__commitMergeAct.setToolTip(self.tr("Commit all the merged"
184 " changes."))
185 self.__abortMergeAct = self.__actionsMenu.addAction(
186 self.tr("Abort Merge"), self.__abortMerge)
187 self.__commitMergeAct.setToolTip(self.tr("Abort an uncommitted merge "
188 "and lose all changes"))
189
190 self.__actionsMenu.addSeparator()
191
192 act = self.__actionsMenu.addAction(
193 self.tr("Adjust column sizes"), self.__resizeColumns)
194 act.setToolTip(self.tr(
195 "Adjusts the width of all columns to their contents"))
196
197 self.actionsButton.setIcon(
198 UI.PixmapCache.getIcon("actionsToolButton"))
199 self.actionsButton.setMenu(self.__actionsMenu)
200
201 def closeEvent(self, e):
202 """
203 Protected slot implementing a close event handler.
204
205 @param e close event (QCloseEvent)
206 """
207 if self.__hgClient.isExecuting():
208 self.__hgClient.cancel()
209
210 if self.__mq:
211 self.vcs.getPlugin().setPreferences(
212 "MqStatusDialogGeometry", self.saveGeometry())
213 self.vcs.getPlugin().setPreferences(
214 "MqStatusDialogSplitterState", self.diffSplitter.saveState())
215 else:
216 self.vcs.getPlugin().setPreferences(
217 "StatusDialogGeometry", self.saveGeometry())
218 self.vcs.getPlugin().setPreferences(
219 "StatusDialogSplitterState", self.diffSplitter.saveState())
220
221 e.accept()
222
223 def show(self):
224 """
225 Public slot to show the dialog.
226 """
227 super().show()
228
229 geom = (
230 self.vcs.getPlugin().getPreferences("MqStatusDialogGeometry")
231 if self.__mq else
232 self.vcs.getPlugin().getPreferences("StatusDialogGeometry")
233 )
234 if geom.isEmpty():
235 s = QSize(800, 600)
236 self.resize(s)
237 else:
238 self.restoreGeometry(geom)
239
240 diffSplitterState = (
241 self.vcs.getPlugin().getPreferences("MqStatusDialogSplitterState")
242 if self.__mq else
243 self.vcs.getPlugin().getPreferences("StatusDialogSplitterState")
244 )
245 if diffSplitterState is not None:
246 self.diffSplitter.restoreState(diffSplitterState)
247
248 def __resort(self):
249 """
250 Private method to resort the tree.
251 """
252 self.statusList.sortItems(
253 self.statusList.sortColumn(),
254 self.statusList.header().sortIndicatorOrder())
255
256 def __resizeColumns(self):
257 """
258 Private method to resize the list columns.
259 """
260 self.statusList.header().resizeSections(
261 QHeaderView.ResizeMode.ResizeToContents)
262 self.statusList.header().setStretchLastSection(True)
263
264 def __generateItem(self, status, path):
265 """
266 Private method to generate a status item in the status list.
267
268 @param status status indicator (string)
269 @param path path of the file or directory (string)
270 """
271 statusText = self.status[status]
272 itm = QTreeWidgetItem(self.statusList, [
273 "",
274 statusText,
275 path,
276 ])
277
278 itm.setTextAlignment(1, Qt.AlignmentFlag.AlignHCenter)
279 itm.setTextAlignment(2, Qt.AlignmentFlag.AlignLeft)
280
281 if status in "AMR":
282 itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable)
283 itm.setCheckState(self.__toBeCommittedColumn,
284 Qt.CheckState.Checked)
285 else:
286 itm.setFlags(itm.flags() & ~Qt.ItemFlag.ItemIsUserCheckable)
287
288 if statusText not in self.__statusFilters:
289 self.__statusFilters.append(statusText)
290
291 def start(self, fn):
292 """
293 Public slot to start the hg status command.
294
295 @param fn filename(s)/directoryname(s) to show the status of
296 (string or list of strings)
297 """
298 self.errorGroup.hide()
299 self.intercept = False
300 self.args = fn
301
302 self.actionsButton.setEnabled(False)
303
304 self.statusFilterCombo.clear()
305 self.__statusFilters = []
306 self.statusList.clear()
307
308 if self.__mq:
309 self.setWindowTitle(
310 self.tr("Mercurial Queue Repository Status"))
311 else:
312 self.setWindowTitle(self.tr('Mercurial Status'))
313
314 args = self.vcs.initCommand("status")
315 if self.__mq:
316 args.append('--mq')
317 else:
318 if self.vcs.hasSubrepositories():
319 args.append("--subrepos")
320
321 if isinstance(fn, list):
322 self.vcs.addArguments(args, fn)
323 else:
324 args.append(fn)
325
326 self.refreshButton.setEnabled(False)
327
328 self.__repoPath = self.__hgClient.getRepository()
329
330 out, err = self.__hgClient.runcommand(args)
331 if err:
332 self.__showError(err)
333 if out:
334 for line in out.splitlines():
335 self.__processOutputLine(line)
336 if self.__hgClient.wasCanceled():
337 break
338 self.__finish()
339
340 def __finish(self):
341 """
342 Private slot called when the process finished or the user pressed
343 the button.
344 """
345 self.refreshButton.setEnabled(True)
346
347 self.buttonBox.button(
348 QDialogButtonBox.StandardButton.Close).setEnabled(True)
349 self.buttonBox.button(
350 QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
351 self.buttonBox.button(
352 QDialogButtonBox.StandardButton.Close).setDefault(True)
353 self.buttonBox.button(
354 QDialogButtonBox.StandardButton.Close).setFocus(
355 Qt.FocusReason.OtherFocusReason)
356
357 self.__statusFilters.sort()
358 self.__statusFilters.insert(0, "<{0}>".format(self.tr("all")))
359 self.statusFilterCombo.addItems(self.__statusFilters)
360
361 if not self.__mq:
362 self.actionsButton.setEnabled(True)
363
364 self.__resort()
365 self.__resizeColumns()
366
367 self.__refreshDiff()
368
369 def on_buttonBox_clicked(self, button):
370 """
371 Private slot called by a button of the button box clicked.
372
373 @param button button that was clicked (QAbstractButton)
374 """
375 if button == self.buttonBox.button(
376 QDialogButtonBox.StandardButton.Close
377 ):
378 self.close()
379 elif button == self.buttonBox.button(
380 QDialogButtonBox.StandardButton.Cancel
381 ):
382 self.__hgClient.cancel()
383 elif button == self.refreshButton:
384 self.on_refreshButton_clicked()
385
386 def __processOutputLine(self, line):
387 """
388 Private method to process the lines of output.
389
390 @param line output line to be processed (string)
391 """
392 if line[0] in "ACIMR?!" and line[1] == " ":
393 status, path = line.strip().split(" ", 1)
394 self.__generateItem(status, path)
395
396 def __showError(self, out):
397 """
398 Private slot to show some error.
399
400 @param out error to be shown (string)
401 """
402 self.errorGroup.show()
403 self.errors.insertPlainText(out)
404 self.errors.ensureCursorVisible()
405
406 @pyqtSlot()
407 def on_refreshButton_clicked(self):
408 """
409 Private slot to refresh the status display.
410 """
411 selectedItems = self.statusList.selectedItems()
412 if len(selectedItems) == 1:
413 self.__selectedName = selectedItems[0].text(self.__pathColumn)
414 else:
415 self.__selectedName = ""
416
417 self.start(self.args)
418
419 @pyqtSlot(int)
420 def on_statusFilterCombo_activated(self, index):
421 """
422 Private slot to react to the selection of a status filter.
423
424 @param index index of the selected entry
425 @type int
426 """
427 txt = self.statusFilterCombo.itemText(index)
428 if txt == "<{0}>".format(self.tr("all")):
429 for topIndex in range(self.statusList.topLevelItemCount()):
430 topItem = self.statusList.topLevelItem(topIndex)
431 topItem.setHidden(False)
432 else:
433 for topIndex in range(self.statusList.topLevelItemCount()):
434 topItem = self.statusList.topLevelItem(topIndex)
435 topItem.setHidden(topItem.text(self.__statusColumn) != txt)
436
437 @pyqtSlot()
438 def on_statusList_itemSelectionChanged(self):
439 """
440 Private slot to act upon changes of selected items.
441 """
442 self.__generateDiffs()
443
444 ###########################################################################
445 ## Menu handling methods
446 ###########################################################################
447
448 def __showActionsMenu(self):
449 """
450 Private slot to prepare the actions button menu before it is shown.
451 """
452 if self.vcs.canCommitMerge():
453 self.__commitMergeAct.setEnabled(True)
454 self.__abortMergeAct.setEnabled(True)
455
456 self.__addAct.setEnabled(False)
457 self.__diffAct.setEnabled(False)
458 self.__sbsDiffAct.setEnabled(False)
459 self.__revertAct.setEnabled(False)
460 self.__forgetAct.setEnabled(False)
461 self.__restoreAct.setEnabled(False)
462 self.__commitAct.setEnabled(False)
463 self.__commitSelectAct.setEnabled(False)
464 self.__commitDeselectAct.setEnabled(False)
465
466 self.__lfAddLargeAct.setEnabled(False)
467 self.__lfAddNormalAct.setEnabled(False)
468
469 else:
470 self.__commitMergeAct.setEnabled(False)
471 self.__abortMergeAct.setEnabled(False)
472
473 modified = len(self.__getModifiedItems())
474 unversioned = len(self.__getUnversionedItems())
475 missing = len(self.__getMissingItems())
476 commitable = len(self.__getCommitableItems())
477 commitableUnselected = len(self.__getCommitableUnselectedItems())
478
479 self.__addAct.setEnabled(unversioned)
480 self.__diffAct.setEnabled(modified)
481 self.__sbsDiffAct.setEnabled(modified == 1)
482 self.__revertAct.setEnabled(modified)
483 self.__forgetAct.setEnabled(missing)
484 self.__restoreAct.setEnabled(missing)
485 self.__commitAct.setEnabled(commitable)
486 self.__commitSelectAct.setEnabled(commitableUnselected)
487 self.__commitDeselectAct.setEnabled(commitable)
488
489 if self.vcs.isExtensionActive("largefiles"):
490 enable = bool(unversioned)
491 else:
492 enable = False
493 self.__lfAddLargeAct.setEnabled(enable)
494 self.__lfAddNormalAct.setEnabled(enable)
495
496 def __commit(self):
497 """
498 Private slot to handle the Commit context menu entry.
499 """
500 if self.__mq:
501 self.vcs.vcsCommit(self.__repoPath, "", mq=True)
502 else:
503 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
504 for itm in self.__getCommitableItems()]
505 if not names:
506 E5MessageBox.information(
507 self,
508 self.tr("Commit"),
509 self.tr("""There are no entries selected to be"""
510 """ committed."""))
511 return
512
513 if Preferences.getVCS("AutoSaveFiles"):
514 vm = e5App().getObject("ViewManager")
515 for name in names:
516 vm.saveEditor(name)
517 self.vcs.vcsCommit(names, '')
518
519 def __committed(self):
520 """
521 Private slot called after the commit has finished.
522 """
523 if self.isVisible():
524 self.on_refreshButton_clicked()
525 self.vcs.checkVCSStatus()
526
527 def __commitSelectAll(self):
528 """
529 Private slot to select all entries for commit.
530 """
531 self.__commitSelect(True)
532
533 def __commitDeselectAll(self):
534 """
535 Private slot to deselect all entries from commit.
536 """
537 self.__commitSelect(False)
538
539 def __add(self):
540 """
541 Private slot to handle the Add context menu entry.
542 """
543 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
544 for itm in self.__getUnversionedItems()]
545 if not names:
546 E5MessageBox.information(
547 self,
548 self.tr("Add"),
549 self.tr("""There are no unversioned entries"""
550 """ available/selected."""))
551 return
552
553 self.vcs.vcsAdd(names)
554 self.on_refreshButton_clicked()
555
556 project = e5App().getObject("Project")
557 for name in names:
558 project.getModel().updateVCSStatus(name)
559 self.vcs.checkVCSStatus()
560
561 def __lfAdd(self, mode):
562 """
563 Private slot to add a file to the repository.
564
565 @param mode add mode (string one of 'normal' or 'large')
566 """
567 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
568 for itm in self.__getUnversionedItems()]
569 if not names:
570 E5MessageBox.information(
571 self,
572 self.tr("Add"),
573 self.tr("""There are no unversioned entries"""
574 """ available/selected."""))
575 return
576
577 self.vcs.getExtensionObject("largefiles").hgAdd(
578 names, mode)
579 self.on_refreshButton_clicked()
580
581 project = e5App().getObject("Project")
582 for name in names:
583 project.getModel().updateVCSStatus(name)
584 self.vcs.checkVCSStatus()
585
586 def __forget(self):
587 """
588 Private slot to handle the Remove context menu entry.
589 """
590 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
591 for itm in self.__getMissingItems()]
592 if not names:
593 E5MessageBox.information(
594 self,
595 self.tr("Remove"),
596 self.tr("""There are no missing entries"""
597 """ available/selected."""))
598 return
599
600 self.vcs.hgForget(names)
601 self.on_refreshButton_clicked()
602
603 def __revert(self):
604 """
605 Private slot to handle the Revert context menu entry.
606 """
607 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
608 for itm in self.__getModifiedItems()]
609 if not names:
610 E5MessageBox.information(
611 self,
612 self.tr("Revert"),
613 self.tr("""There are no uncommitted changes"""
614 """ available/selected."""))
615 return
616
617 self.vcs.hgRevert(names)
618 self.raise_()
619 self.activateWindow()
620 self.on_refreshButton_clicked()
621
622 project = e5App().getObject("Project")
623 for name in names:
624 project.getModel().updateVCSStatus(name)
625 self.vcs.checkVCSStatus()
626
627 def __restoreMissing(self):
628 """
629 Private slot to handle the Restore Missing context menu entry.
630 """
631 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
632 for itm in self.__getMissingItems()]
633 if not names:
634 E5MessageBox.information(
635 self,
636 self.tr("Revert"),
637 self.tr("""There are no missing entries"""
638 """ available/selected."""))
639 return
640
641 self.vcs.hgRevert(names)
642 self.on_refreshButton_clicked()
643 self.vcs.checkVCSStatus()
644
645 def __diff(self):
646 """
647 Private slot to handle the Diff context menu entry.
648 """
649 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
650 for itm in self.__getModifiedItems()]
651 if not names:
652 E5MessageBox.information(
653 self,
654 self.tr("Differences"),
655 self.tr("""There are no uncommitted changes"""
656 """ available/selected."""))
657 return
658
659 if self.diff is None:
660 from .HgDiffDialog import HgDiffDialog
661 self.diff = HgDiffDialog(self.vcs)
662 self.diff.show()
663 self.diff.start(names, refreshable=True)
664
665 def __sbsDiff(self):
666 """
667 Private slot to handle the Diff context menu entry.
668 """
669 names = [os.path.join(self.__repoPath, itm.text(self.__pathColumn))
670 for itm in self.__getModifiedItems()]
671 if not names:
672 E5MessageBox.information(
673 self,
674 self.tr("Side-by-Side Diff"),
675 self.tr("""There are no uncommitted changes"""
676 """ available/selected."""))
677 return
678 elif len(names) > 1:
679 E5MessageBox.information(
680 self,
681 self.tr("Side-by-Side Diff"),
682 self.tr("""Only one file with uncommitted changes"""
683 """ must be selected."""))
684 return
685
686 self.vcs.hgSbsDiff(names[0])
687
688 def __getCommitableItems(self):
689 """
690 Private method to retrieve all entries the user wants to commit.
691
692 @return list of all items, the user has checked
693 """
694 commitableItems = []
695 for index in range(self.statusList.topLevelItemCount()):
696 itm = self.statusList.topLevelItem(index)
697 if (
698 itm.checkState(self.__toBeCommittedColumn) ==
699 Qt.CheckState.Checked
700 ):
701 commitableItems.append(itm)
702 return commitableItems
703
704 def __getCommitableUnselectedItems(self):
705 """
706 Private method to retrieve all entries the user may commit but hasn't
707 selected.
708
709 @return list of all items, the user has checked
710 """
711 items = []
712 for index in range(self.statusList.topLevelItemCount()):
713 itm = self.statusList.topLevelItem(index)
714 if (
715 itm.flags() & Qt.ItemFlag.ItemIsUserCheckable and
716 itm.checkState(self.__toBeCommittedColumn) ==
717 Qt.CheckState.Unchecked
718 ):
719 items.append(itm)
720 return items
721
722 def __getModifiedItems(self):
723 """
724 Private method to retrieve all entries, that have a modified status.
725
726 @return list of all items with a modified status
727 """
728 modifiedItems = []
729 for itm in self.statusList.selectedItems():
730 if itm.text(self.__statusColumn) in self.modifiedIndicators:
731 modifiedItems.append(itm)
732 return modifiedItems
733
734 def __getUnversionedItems(self):
735 """
736 Private method to retrieve all entries, that have an unversioned
737 status.
738
739 @return list of all items with an unversioned status
740 """
741 unversionedItems = []
742 for itm in self.statusList.selectedItems():
743 if itm.text(self.__statusColumn) in self.unversionedIndicators:
744 unversionedItems.append(itm)
745 return unversionedItems
746
747 def __getMissingItems(self):
748 """
749 Private method to retrieve all entries, that have a missing status.
750
751 @return list of all items with a missing status
752 """
753 missingItems = []
754 for itm in self.statusList.selectedItems():
755 if itm.text(self.__statusColumn) in self.missingIndicators:
756 missingItems.append(itm)
757 return missingItems
758
759 def __commitSelect(self, selected):
760 """
761 Private slot to select or deselect all entries.
762
763 @param selected commit selection state to be set (boolean)
764 """
765 for index in range(self.statusList.topLevelItemCount()):
766 itm = self.statusList.topLevelItem(index)
767 if itm.flags() & Qt.ItemFlag.ItemIsUserCheckable:
768 if selected:
769 itm.setCheckState(self.__toBeCommittedColumn,
770 Qt.CheckState.Checked)
771 else:
772 itm.setCheckState(self.__toBeCommittedColumn,
773 Qt.CheckState.Unchecked)
774
775 def __commitMerge(self):
776 """
777 Private slot to handle the Commit Merge context menu entry.
778 """
779 self.vcs.vcsCommit(self.__repoPath, self.tr('Merge'), merge=True)
780 self.__committed()
781
782 def __abortMerge(self):
783 """
784 Private slot used to abort an uncommitted merge.
785 """
786 self.vcs.hgAbortMerge()
787 self.__committed()
788
789 ###########################################################################
790 ## Diff handling methods below
791 ###########################################################################
792
793 def __generateDiffs(self):
794 """
795 Private slot to generate diff outputs for the selected item.
796 """
797 self.diffEdit.clear()
798 self.diffHighlighter.regenerateRules()
799
800 if not self.__mq:
801 selectedItems = self.statusList.selectedItems()
802 if len(selectedItems) == 1:
803 fn = os.path.join(self.__repoPath,
804 selectedItems[0].text(self.__pathColumn))
805 self.__diffGenerator.start(fn)
806
807 def __generatorFinished(self):
808 """
809 Private slot connected to the finished signal of the diff generator.
810 """
811 diff = self.__diffGenerator.getResult()[0]
812
813 if diff:
814 for line in diff[:]:
815 if line.startswith("@@ "):
816 break
817 else:
818 diff.pop(0)
819 self.diffEdit.setPlainText("".join(diff))
820
821 tc = self.diffEdit.textCursor()
822 tc.movePosition(QTextCursor.MoveOperation.Start)
823 self.diffEdit.setTextCursor(tc)
824 self.diffEdit.ensureCursorVisible()
825
826 def __refreshDiff(self):
827 """
828 Private method to refresh the diff output after a refresh.
829 """
830 if self.__selectedName and not self.__mq:
831 for index in range(self.statusList.topLevelItemCount()):
832 itm = self.statusList.topLevelItem(index)
833 if itm.text(self.__pathColumn) == self.__selectedName:
834 itm.setSelected(True)
835 break
836
837 self.__selectedName = ""

eric ide

mercurial