src/eric7/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/Plugins/VcsPlugins/vcsGit/GitLogBrowserDialog.py	Wed Jul 13 14:55:47 2022 +0200
@@ -13,15 +13,17 @@
 import contextlib
 import pathlib
 
-from PyQt6.QtCore import (
-    pyqtSlot, Qt, QDate, QProcess, QTimer, QSize, QPoint
-)
-from PyQt6.QtGui import (
-    QColor, QPixmap, QPainter, QPen, QIcon, QTextCursor, QPalette
-)
+from PyQt6.QtCore import pyqtSlot, Qt, QDate, QProcess, QTimer, QSize, QPoint
+from PyQt6.QtGui import QColor, QPixmap, QPainter, QPen, QIcon, QTextCursor, QPalette
 from PyQt6.QtWidgets import (
-    QWidget, QDialogButtonBox, QHeaderView, QTreeWidgetItem, QApplication,
-    QLineEdit, QMenu, QInputDialog
+    QWidget,
+    QDialogButtonBox,
+    QHeaderView,
+    QTreeWidgetItem,
+    QApplication,
+    QLineEdit,
+    QMenu,
+    QInputDialog,
 )
 
 from EricWidgets.EricApplication import ericApp
@@ -38,21 +40,47 @@
 import UI.PixmapCache
 import Preferences
 
-COLORNAMES = ["red", "green", "purple", "cyan", "olive", "magenta",
-              "gray", "yellow", "darkred", "darkgreen", "darkblue",
-              "darkcyan", "darkmagenta", "blue"]
+COLORNAMES = [
+    "red",
+    "green",
+    "purple",
+    "cyan",
+    "olive",
+    "magenta",
+    "gray",
+    "yellow",
+    "darkred",
+    "darkgreen",
+    "darkblue",
+    "darkcyan",
+    "darkmagenta",
+    "blue",
+]
 COLORS = [str(QColor(x).name()) for x in COLORNAMES]
 
-LIGHTCOLORS = ["#aaaaff", "#7faa7f", "#ffaaaa", "#aaffaa", "#7f7faa",
-               "#ffaaff", "#aaffff", "#d5d579", "#ffaaff", "#d57979",
-               "#d579d5", "#79d5d5", "#d5d5d5", "#d5d500",
-               ]
+LIGHTCOLORS = [
+    "#aaaaff",
+    "#7faa7f",
+    "#ffaaaa",
+    "#aaffaa",
+    "#7f7faa",
+    "#ffaaff",
+    "#aaffff",
+    "#d5d579",
+    "#ffaaff",
+    "#d57979",
+    "#d579d5",
+    "#79d5d5",
+    "#d5d5d5",
+    "#d5d500",
+]
 
 
 class GitLogBrowserDialog(QWidget, Ui_GitLogBrowserDialog):
     """
     Class implementing a dialog to browse the log history.
     """
+
     IconColumn = 0
     CommitIdColumn = 1
     AuthorColumn = 2
@@ -62,73 +90,70 @@
     SubjectColumn = 6
     BranchColumn = 7
     TagsColumn = 8
-    
+
     def __init__(self, vcs, parent=None):
         """
         Constructor
-        
+
         @param vcs reference to the vcs object
         @param parent parent widget (QWidget)
         """
         super().__init__(parent)
         self.setupUi(self)
-        
+
         windowFlags = self.windowFlags()
         windowFlags |= Qt.WindowType.WindowContextHelpButtonHint
         self.setWindowFlags(windowFlags)
-        
+
         self.mainSplitter.setSizes([300, 400])
         self.mainSplitter.setStretchFactor(0, 1)
         self.mainSplitter.setStretchFactor(1, 2)
         self.diffSplitter.setStretchFactor(0, 1)
         self.diffSplitter.setStretchFactor(1, 2)
-        
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Close).setEnabled(False)
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Cancel).setDefault(True)
-        
+
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
+
         self.filesTree.headerItem().setText(self.filesTree.columnCount(), "")
-        self.filesTree.header().setSortIndicator(
-            1, Qt.SortOrder.AscendingOrder)
-        
+        self.filesTree.header().setSortIndicator(1, Qt.SortOrder.AscendingOrder)
+
         self.upButton.setIcon(UI.PixmapCache.getIcon("1uparrow"))
         self.downButton.setIcon(UI.PixmapCache.getIcon("1downarrow"))
-        
+
         self.refreshButton = self.buttonBox.addButton(
-            self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole)
-        self.refreshButton.setToolTip(
-            self.tr("Press to refresh the list of commits"))
+            self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole
+        )
+        self.refreshButton.setToolTip(self.tr("Press to refresh the list of commits"))
         self.refreshButton.setEnabled(False)
-        
+
         self.findPrevButton.setIcon(UI.PixmapCache.getIcon("1leftarrow"))
         self.findNextButton.setIcon(UI.PixmapCache.getIcon("1rightarrow"))
         self.__findBackwards = False
-        
+
         self.modeComboBox.addItem(self.tr("Find"), "find")
         self.modeComboBox.addItem(self.tr("Filter"), "filter")
-        
+
         self.fieldCombo.addItem(self.tr("Commit ID"), "commitId")
         self.fieldCombo.addItem(self.tr("Author"), "author")
         self.fieldCombo.addItem(self.tr("Committer"), "committer")
         self.fieldCombo.addItem(self.tr("Subject"), "subject")
         self.fieldCombo.addItem(self.tr("File"), "file")
-        
+
         self.__logTreeNormalFont = self.logTree.font()
         self.__logTreeNormalFont.setBold(False)
         self.__logTreeBoldFont = self.logTree.font()
         self.__logTreeBoldFont.setBold(True)
         self.__logTreeHasDarkBackground = ericApp().usesDarkPalette()
-        
+
         font = Preferences.getEditorOtherFonts("MonospacedFont")
         self.diffEdit.document().setDefaultFont(font)
-        
+
         self.diffHighlighter = GitDiffHighlighter(self.diffEdit.document())
         self.__diffGenerator = GitDiffGenerator(vcs, self)
         self.__diffGenerator.finished.connect(self.__generatorFinished)
-        
+
         self.vcs = vcs
-        
+
         self.__detailsTemplate = self.tr(
             "<table>"
             "<tr><td><b>Commit ID</b></td><td>{0}</td></tr>"
@@ -141,50 +166,44 @@
             "{9}"
             "</table>"
         )
-        self.__parentsTemplate = self.tr(
-            "<tr><td><b>Parents</b></td><td>{0}</td></tr>"
-        )
+        self.__parentsTemplate = self.tr("<tr><td><b>Parents</b></td><td>{0}</td></tr>")
         self.__childrenTemplate = self.tr(
             "<tr><td><b>Children</b></td><td>{0}</td></tr>"
         )
         self.__branchesTemplate = self.tr(
             "<tr><td><b>Branches</b></td><td>{0}</td></tr>"
         )
-        self.__tagsTemplate = self.tr(
-            "<tr><td><b>Tags</b></td><td>{0}</td></tr>"
-        )
-        self.__mesageTemplate = self.tr(
-            "<tr><td><b>Message</b></td><td>{0}</td></tr>"
-        )
-        
+        self.__tagsTemplate = self.tr("<tr><td><b>Tags</b></td><td>{0}</td></tr>")
+        self.__mesageTemplate = self.tr("<tr><td><b>Message</b></td><td>{0}</td></tr>")
+
         self.__formatTemplate = (
-            'format:recordstart%n'
-            'commit|%h%n'
-            'parents|%p%n'
-            'author|%an%n'
-            'authormail|%ae%n'
-            'authordate|%ai%n'
-            'committer|%cn%n'
-            'committermail|%ce%n'
-            'committerdate|%ci%n'
-            'refnames|%d%n'
-            'subject|%s%n'
-            'bodystart%n'
-            '%b%n'
-            'bodyend%n'
+            "format:recordstart%n"
+            "commit|%h%n"
+            "parents|%p%n"
+            "author|%an%n"
+            "authormail|%ae%n"
+            "authordate|%ai%n"
+            "committer|%cn%n"
+            "committermail|%ce%n"
+            "committerdate|%ci%n"
+            "refnames|%d%n"
+            "subject|%s%n"
+            "bodystart%n"
+            "%b%n"
+            "bodyend%n"
         )
-        
+
         self.__filename = ""
         self.__isFile = False
         self.__selectedCommitIDs = []
         self.intercept = False
-        
+
         self.__initData()
-        
+
         self.fromDate.setDisplayFormat("yyyy-MM-dd")
         self.toDate.setDisplayFormat("yyyy-MM-dd")
         self.__resetUI()
-        
+
         # roles used in the log tree
         self.__subjectRole = Qt.ItemDataRole.UserRole
         self.__messageRole = Qt.ItemDataRole.UserRole + 1
@@ -194,120 +213,107 @@
         self.__branchesRole = Qt.ItemDataRole.UserRole + 5
         self.__authorMailRole = Qt.ItemDataRole.UserRole + 6
         self.__committerMailRole = Qt.ItemDataRole.UserRole + 7
-        
+
         # roles used in the file tree
         self.__diffFileLineRole = Qt.ItemDataRole.UserRole
-        
+
         self.__process = EricOverrideCursorProcess()
         self.__process.finished.connect(self.__procFinished)
         self.__process.readyReadStandardOutput.connect(self.__readStdout)
         self.__process.readyReadStandardError.connect(self.__readStderr)
-        
+
         self.flags = {
-            'A': self.tr('Added'),
-            'D': self.tr('Deleted'),
-            'M': self.tr('Modified'),
-            'C': self.tr('Copied'),
-            'R': self.tr('Renamed'),
-            'T': self.tr('Type changed'),
-            'U': self.tr('Unmerged'),
-            'X': self.tr('Unknown'),
+            "A": self.tr("Added"),
+            "D": self.tr("Deleted"),
+            "M": self.tr("Modified"),
+            "C": self.tr("Copied"),
+            "R": self.tr("Renamed"),
+            "T": self.tr("Type changed"),
+            "U": self.tr("Unmerged"),
+            "X": self.tr("Unknown"),
         }
-        
+
         self.__dotRadius = 8
         self.__rowHeight = 20
-        
-        self.logTree.setIconSize(
-            QSize(100 * self.__rowHeight, self.__rowHeight))
-        
+
+        self.logTree.setIconSize(QSize(100 * self.__rowHeight, self.__rowHeight))
+
         self.detailsEdit.anchorClicked.connect(self.__commitIdClicked)
-        
+
         self.__initLogTreeContextMenu()
         self.__initActionsMenu()
-        
+
         self.__finishCallbacks = []
-    
+
     def __addFinishCallback(self, callback):
         """
         Private method to add a method to be called once the process finished.
-        
+
         The callback methods are invoke in a FIFO style and are consumed. If
         a callback method needs to be called again, it must be added again.
-        
+
         @param callback callback method
         @type function
         """
         if callback not in self.__finishCallbacks:
             self.__finishCallbacks.append(callback)
-    
+
     def __initLogTreeContextMenu(self):
         """
         Private method to initialize the log tree context menu.
         """
         self.__logTreeMenu = QMenu()
-        
+
         # commit ID column
-        act = self.__logTreeMenu.addAction(
-            self.tr("Show Commit ID Column"))
-        act.setToolTip(self.tr(
-            "Press to show the commit ID column"))
+        act = self.__logTreeMenu.addAction(self.tr("Show Commit ID Column"))
+        act.setToolTip(self.tr("Press to show the commit ID column"))
         act.setCheckable(True)
-        act.setChecked(self.vcs.getPlugin().getPreferences(
-            "ShowCommitIdColumn"))
+        act.setChecked(self.vcs.getPlugin().getPreferences("ShowCommitIdColumn"))
         act.triggered.connect(self.__showCommitIdColumn)
-        
+
         # author and date columns
-        act = self.__logTreeMenu.addAction(
-            self.tr("Show Author Columns"))
-        act.setToolTip(self.tr(
-            "Press to show the author columns"))
+        act = self.__logTreeMenu.addAction(self.tr("Show Author Columns"))
+        act.setToolTip(self.tr("Press to show the author columns"))
         act.setCheckable(True)
-        act.setChecked(self.vcs.getPlugin().getPreferences(
-            "ShowAuthorColumns"))
+        act.setChecked(self.vcs.getPlugin().getPreferences("ShowAuthorColumns"))
         act.triggered.connect(self.__showAuthorColumns)
-        
+
         # committer and commit date columns
-        act = self.__logTreeMenu.addAction(
-            self.tr("Show Committer Columns"))
-        act.setToolTip(self.tr(
-            "Press to show the committer columns"))
+        act = self.__logTreeMenu.addAction(self.tr("Show Committer Columns"))
+        act.setToolTip(self.tr("Press to show the committer columns"))
         act.setCheckable(True)
-        act.setChecked(self.vcs.getPlugin().getPreferences(
-            "ShowCommitterColumns"))
+        act.setChecked(self.vcs.getPlugin().getPreferences("ShowCommitterColumns"))
         act.triggered.connect(self.__showCommitterColumns)
-        
+
         # branches column
-        act = self.__logTreeMenu.addAction(
-            self.tr("Show Branches Column"))
-        act.setToolTip(self.tr(
-            "Press to show the branches column"))
+        act = self.__logTreeMenu.addAction(self.tr("Show Branches Column"))
+        act.setToolTip(self.tr("Press to show the branches column"))
         act.setCheckable(True)
-        act.setChecked(self.vcs.getPlugin().getPreferences(
-            "ShowBranchesColumn"))
+        act.setChecked(self.vcs.getPlugin().getPreferences("ShowBranchesColumn"))
         act.triggered.connect(self.__showBranchesColumn)
-        
+
         # tags column
-        act = self.__logTreeMenu.addAction(
-            self.tr("Show Tags Column"))
-        act.setToolTip(self.tr(
-            "Press to show the Tags column"))
+        act = self.__logTreeMenu.addAction(self.tr("Show Tags Column"))
+        act.setToolTip(self.tr("Press to show the Tags column"))
         act.setCheckable(True)
-        act.setChecked(self.vcs.getPlugin().getPreferences(
-            "ShowTagsColumn"))
+        act.setChecked(self.vcs.getPlugin().getPreferences("ShowTagsColumn"))
         act.triggered.connect(self.__showTagsColumn)
-        
+
         # set column visibility as configured
-        self.__showCommitIdColumn(self.vcs.getPlugin().getPreferences(
-            "ShowCommitIdColumn"))
-        self.__showAuthorColumns(self.vcs.getPlugin().getPreferences(
-            "ShowAuthorColumns"))
-        self.__showCommitterColumns(self.vcs.getPlugin().getPreferences(
-            "ShowCommitterColumns"))
-        self.__showBranchesColumn(self.vcs.getPlugin().getPreferences(
-            "ShowBranchesColumn"))
-        self.__showTagsColumn(self.vcs.getPlugin().getPreferences(
-            "ShowTagsColumn"))
-    
+        self.__showCommitIdColumn(
+            self.vcs.getPlugin().getPreferences("ShowCommitIdColumn")
+        )
+        self.__showAuthorColumns(
+            self.vcs.getPlugin().getPreferences("ShowAuthorColumns")
+        )
+        self.__showCommitterColumns(
+            self.vcs.getPlugin().getPreferences("ShowCommitterColumns")
+        )
+        self.__showBranchesColumn(
+            self.vcs.getPlugin().getPreferences("ShowBranchesColumn")
+        )
+        self.__showTagsColumn(self.vcs.getPlugin().getPreferences("ShowTagsColumn"))
+
     def __initActionsMenu(self):
         """
         Private method to initialize the actions menu.
@@ -315,48 +321,62 @@
         self.__actionsMenu = QMenu()
         self.__actionsMenu.setTearOffEnabled(True)
         self.__actionsMenu.setToolTipsVisible(True)
-        
+
         self.__cherryAct = self.__actionsMenu.addAction(
-            self.tr("Copy Commits"), self.__cherryActTriggered)
-        self.__cherryAct.setToolTip(self.tr(
-            "Cherry-pick the selected commits to the current branch"))
-        
+            self.tr("Copy Commits"), self.__cherryActTriggered
+        )
+        self.__cherryAct.setToolTip(
+            self.tr("Cherry-pick the selected commits to the current branch")
+        )
+
         self.__actionsMenu.addSeparator()
-        
+
         self.__tagAct = self.__actionsMenu.addAction(
-            self.tr("Tag"), self.__tagActTriggered)
+            self.tr("Tag"), self.__tagActTriggered
+        )
         self.__tagAct.setToolTip(self.tr("Tag the selected commit"))
-        
+
         self.__branchAct = self.__actionsMenu.addAction(
-            self.tr("Branch"), self.__branchActTriggered)
-        self.__branchAct.setToolTip(self.tr(
-            "Create a new branch at the selected commit."))
+            self.tr("Branch"), self.__branchActTriggered
+        )
+        self.__branchAct.setToolTip(
+            self.tr("Create a new branch at the selected commit.")
+        )
         self.__branchSwitchAct = self.__actionsMenu.addAction(
-            self.tr("Branch && Switch"), self.__branchSwitchActTriggered)
-        self.__branchSwitchAct.setToolTip(self.tr(
-            "Create a new branch at the selected commit and switch"
-            " the work tree to it."))
-        
+            self.tr("Branch && Switch"), self.__branchSwitchActTriggered
+        )
+        self.__branchSwitchAct.setToolTip(
+            self.tr(
+                "Create a new branch at the selected commit and switch"
+                " the work tree to it."
+            )
+        )
+
         self.__switchAct = self.__actionsMenu.addAction(
-            self.tr("Switch"), self.__switchActTriggered)
-        self.__switchAct.setToolTip(self.tr(
-            "Switch the working directory to the selected commit"))
+            self.tr("Switch"), self.__switchActTriggered
+        )
+        self.__switchAct.setToolTip(
+            self.tr("Switch the working directory to the selected commit")
+        )
         self.__actionsMenu.addSeparator()
-        
+
         self.__shortlogAct = self.__actionsMenu.addAction(
-            self.tr("Show Short Log"), self.__shortlogActTriggered)
-        self.__shortlogAct.setToolTip(self.tr(
-            "Show a dialog with a log output for release notes"))
-        
+            self.tr("Show Short Log"), self.__shortlogActTriggered
+        )
+        self.__shortlogAct.setToolTip(
+            self.tr("Show a dialog with a log output for release notes")
+        )
+
         self.__describeAct = self.__actionsMenu.addAction(
-            self.tr("Describe"), self.__describeActTriggered)
-        self.__describeAct.setToolTip(self.tr(
-            "Show the most recent tag reachable from a commit"))
-        
-        self.actionsButton.setIcon(
-            UI.PixmapCache.getIcon("actionsToolButton"))
+            self.tr("Describe"), self.__describeActTriggered
+        )
+        self.__describeAct.setToolTip(
+            self.tr("Show the most recent tag reachable from a commit")
+        )
+
+        self.actionsButton.setIcon(UI.PixmapCache.getIcon("actionsToolButton"))
         self.actionsButton.setMenu(self.__actionsMenu)
-    
+
     def __initData(self):
         """
         Private method to (re-)initialize some data.
@@ -364,48 +384,48 @@
         self.__maxDate = QDate()
         self.__minDate = QDate()
         self.__filterLogsEnabled = True
-        
-        self.buf = []        # buffer for stdout
+
+        self.buf = []  # buffer for stdout
         self.diff = None
         self.__started = False
         self.__skipEntries = 0
         self.projectMode = False
-        
+
         # attributes to store log graph data
         self.__commitIds = []
         self.__commitColors = {}
         self.__commitColor = 0
-        
+
         self.__projectRevision = ""
-        
+
         self.__childrenInfo = collections.defaultdict(list)
-    
+
     def closeEvent(self, e):
         """
         Protected slot implementing a close event handler.
-        
+
         @param e close event (QCloseEvent)
         """
         if (
-            self.__process is not None and
-            self.__process.state() != QProcess.ProcessState.NotRunning
+            self.__process is not None
+            and self.__process.state() != QProcess.ProcessState.NotRunning
         ):
             self.__process.terminate()
             QTimer.singleShot(2000, self.__process.kill)
             self.__process.waitForFinished(3000)
-        
+
+        self.vcs.getPlugin().setPreferences("LogBrowserGeometry", self.saveGeometry())
         self.vcs.getPlugin().setPreferences(
-            "LogBrowserGeometry", self.saveGeometry())
-        self.vcs.getPlugin().setPreferences(
-            "LogBrowserSplitterStates", [
+            "LogBrowserSplitterStates",
+            [
                 self.mainSplitter.saveState(),
                 self.detailsSplitter.saveState(),
                 self.diffSplitter.saveState(),
-            ]
+            ],
         )
-        
+
         e.accept()
-    
+
     def show(self):
         """
         Public slot to show the dialog.
@@ -413,9 +433,9 @@
         self.__reloadGeometry()
         self.__restoreSplitterStates()
         self.__resetUI()
-        
+
         super().show()
-    
+
     def __reloadGeometry(self):
         """
         Private method to restore the geometry.
@@ -426,19 +446,18 @@
             self.resize(s)
         else:
             self.restoreGeometry(geom)
-    
+
     def __restoreSplitterStates(self):
         """
         Private method to restore the state of the various splitters.
         """
-        states = self.vcs.getPlugin().getPreferences(
-            "LogBrowserSplitterStates")
+        states = self.vcs.getPlugin().getPreferences("LogBrowserSplitterStates")
         if len(states) == 3:
             # we have three splitters
             self.mainSplitter.restoreState(states[0])
             self.detailsSplitter.restoreState(states[1])
             self.diffSplitter.restoreState(states[2])
-    
+
     def __resetUI(self):
         """
         Private method to reset the user interface.
@@ -446,29 +465,27 @@
         self.fromDate.setDate(QDate.currentDate())
         self.toDate.setDate(QDate.currentDate())
         self.fieldCombo.setCurrentIndex(self.fieldCombo.findData("subject"))
-        self.limitSpinBox.setValue(self.vcs.getPlugin().getPreferences(
-            "LogLimit"))
-        self.stopCheckBox.setChecked(self.vcs.getPlugin().getPreferences(
-            "StopLogOnCopy"))
-        
+        self.limitSpinBox.setValue(self.vcs.getPlugin().getPreferences("LogLimit"))
+        self.stopCheckBox.setChecked(
+            self.vcs.getPlugin().getPreferences("StopLogOnCopy")
+        )
+
         self.logTree.clear()
-    
+
     def __resizeColumnsLog(self):
         """
         Private method to resize the log tree columns.
         """
-        self.logTree.header().resizeSections(
-            QHeaderView.ResizeMode.ResizeToContents)
+        self.logTree.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
         self.logTree.header().setStretchLastSection(True)
-    
+
     def __resizeColumnsFiles(self):
         """
         Private method to resize the changed files tree columns.
         """
-        self.filesTree.header().resizeSections(
-            QHeaderView.ResizeMode.ResizeToContents)
+        self.filesTree.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
         self.filesTree.header().setStretchLastSection(True)
-    
+
     def __resortFiles(self):
         """
         Private method to resort the changed files tree.
@@ -476,11 +493,11 @@
         self.filesTree.setSortingEnabled(True)
         self.filesTree.sortItems(1, Qt.SortOrder.AscendingOrder)
         self.filesTree.setSortingEnabled(False)
-    
+
     def __getColor(self, n):
         """
         Private method to get the (rotating) name of the color given an index.
-        
+
         @param n color index
         @type int
         @return color name
@@ -490,11 +507,11 @@
             return LIGHTCOLORS[n % len(LIGHTCOLORS)]
         else:
             return COLORS[n % len(COLORS)]
-    
+
     def __generateEdges(self, commitId, parents):
         """
         Private method to generate edge info for the give data.
-        
+
         @param commitId commit id to calculate edge info for (string)
         @param parents list of parent commits (list of strings)
         @return tuple containing the column and color index for
@@ -507,15 +524,15 @@
             self.__commitIds.append(commitId)
             self.__commitColors[commitId] = self.__commitColor
             self.__commitColor += 1
-        
+
         col = self.__commitIds.index(commitId)
         color = self.__commitColors.pop(commitId)
         nextCommitIds = self.__commitIds[:]
-        
+
         # add parents to next
         addparents = [p for p in parents if p not in nextCommitIds]
-        nextCommitIds[col:col + 1] = addparents
-        
+        nextCommitIds[col : col + 1] = addparents
+
         # set colors for the parents
         for i, p in enumerate(addparents):
             if not i:
@@ -523,30 +540,35 @@
             else:
                 self.__commitColors[p] = self.__commitColor
                 self.__commitColor += 1
-        
+
         # add edges to the graph
         edges = []
         if parents:
             for ecol, ecommitId in enumerate(self.__commitIds):
                 if ecommitId in nextCommitIds:
                     edges.append(
-                        (ecol, nextCommitIds.index(ecommitId),
-                         self.__commitColors[ecommitId]))
+                        (
+                            ecol,
+                            nextCommitIds.index(ecommitId),
+                            self.__commitColors[ecommitId],
+                        )
+                    )
                 elif ecommitId == commitId:
                     for p in parents:
                         edges.append(
-                            (ecol, nextCommitIds.index(p),
-                             self.__commitColors[p]))
-        
+                            (ecol, nextCommitIds.index(p), self.__commitColors[p])
+                        )
+
         self.__commitIds = nextCommitIds
         return col, color, edges
-    
-    def __generateIcon(self, column, color, bottomedges, topedges, dotColor,
-                       currentCommit):
+
+    def __generateIcon(
+        self, column, color, bottomedges, topedges, dotColor, currentCommit
+    ):
         """
         Private method to generate an icon containing the revision tree for the
         given data.
-        
+
         @param column column index of the revision (integer)
         @param color color of the node (integer)
         @param bottomedges list of edges for the bottom of the node
@@ -558,30 +580,30 @@
             current commit (boolean)
         @return icon for the node (QIcon)
         """
+
         def col2x(col, radius):
             """
             Local function to calculate a x-position for a column.
-            
+
             @param col column number (integer)
             @param radius radius of the indicator circle (integer)
             """
             return int(1.2 * radius) * col + radius // 2 + 3
-        
+
         radius = self.__dotRadius
         w = len(bottomedges) * radius + 20
         h = self.__rowHeight
-        
+
         dot_x = col2x(column, radius) - radius // 2
         dot_y = h // 2
-        
+
         pix = QPixmap(w, h)
-        pix.fill(QColor(0, 0, 0, 0))        # draw transparent background
+        pix.fill(QColor(0, 0, 0, 0))  # draw transparent background
         painter = QPainter(pix)
         painter.setRenderHint(QPainter.RenderHint.Antialiasing)
-        
+
         # draw the revision history lines
-        for y1, y2, lines in ((0, h, bottomedges),
-                              (-h, 0, topedges)):
+        for y1, y2, lines in ((0, h, bottomedges), (-h, 0, topedges)):
             if lines:
                 for start, end, ecolor in lines:
                     lpen = QPen(QColor(self.__getColor(ecolor)))
@@ -590,12 +612,12 @@
                     x1 = col2x(start, radius)
                     x2 = col2x(end, radius)
                     painter.drawLine(x1, dot_y + y1, x2, dot_y + y2)
-        
+
         penradius = 1
         pencolor = self.logTree.palette().color(QPalette.ColorRole.Text)
-        
+
         dot_y = (h // 2) - radius // 2
-        
+
         # draw a dot for the revision
         if currentCommit:
             # enlarge dot for the current revision
@@ -610,53 +632,64 @@
         painter.drawEllipse(dot_x, dot_y, radius, radius)
         painter.end()
         return QIcon(pix)
-    
+
     def __identifyProject(self):
         """
         Private method to determine the revision of the project directory.
         """
         errMsg = ""
-        
+
         args = self.vcs.initCommand("show")
-        args.append("--abbrev={0}".format(
-            self.vcs.getPlugin().getPreferences("CommitIdLength")))
+        args.append(
+            "--abbrev={0}".format(self.vcs.getPlugin().getPreferences("CommitIdLength"))
+        )
         args.append("--format=%h")
         args.append("--no-patch")
         args.append("HEAD")
-        
+
         output = ""
         process = QProcess()
         process.setWorkingDirectory(self.repodir)
-        process.start('git', args)
+        process.start("git", args)
         procStarted = process.waitForStarted(5000)
         if procStarted:
             finished = process.waitForFinished(30000)
             if finished and process.exitCode() == 0:
-                output = str(process.readAllStandardOutput(),
-                             Preferences.getSystem("IOEncoding"),
-                             'replace')
+                output = str(
+                    process.readAllStandardOutput(),
+                    Preferences.getSystem("IOEncoding"),
+                    "replace",
+                )
             else:
                 if not finished:
-                    errMsg = self.tr(
-                        "The git process did not finish within 30s.")
+                    errMsg = self.tr("The git process did not finish within 30s.")
         else:
             errMsg = self.tr("Could not start the git executable.")
-        
+
         if errMsg:
-            EricMessageBox.critical(
-                self,
-                self.tr("Git Error"),
-                errMsg)
-        
+            EricMessageBox.critical(self, self.tr("Git Error"), errMsg)
+
         if output:
             self.__projectRevision = output.strip()
-    
-    def __generateLogItem(self, author, date, committer, commitDate, subject,
-                          message, commitId, changedPaths, parents, refnames,
-                          authorMail, committerMail):
+
+    def __generateLogItem(
+        self,
+        author,
+        date,
+        committer,
+        commitDate,
+        subject,
+        message,
+        commitId,
+        changedPaths,
+        parents,
+        refnames,
+        authorMail,
+        committerMail,
+    ):
         """
         Private method to generate a log tree entry.
-        
+
         @param author author info (string)
         @param date date info (string)
         @param committer committer info (string)
@@ -692,9 +725,10 @@
                     else:
                         branches.append(name)
                     allBranches.append(name)
-        
+
         logMessageColumnWidth = self.vcs.getPlugin().getPreferences(
-            "LogSubjectColumnWidth")
+            "LogSubjectColumnWidth"
+        )
         msgtxt = subject
         if logMessageColumnWidth and len(msgtxt) > logMessageColumnWidth:
             msgtxt = "{0}...".format(msgtxt[:logMessageColumnWidth])
@@ -710,10 +744,10 @@
             ", ".join(tags),
         ]
         itm = QTreeWidgetItem(self.logTree, columnLabels)
-        
+
         parents = [p.strip() for p in parents.split()]
         column, color, edges = self.__generateEdges(commitId, parents)
-        
+
         itm.setData(0, self.__subjectRole, subject)
         itm.setData(0, self.__messageRole, message)
         itm.setData(0, self.__changesRole, changedPaths)
@@ -727,26 +761,31 @@
             itm.setData(0, self.__parentsRole, parents)
             for parent in parents:
                 self.__childrenInfo[parent].append(commitId)
-        
+
         topedges = (
-            self.logTree.topLevelItem(
-                self.logTree.indexOfTopLevelItem(itm) - 1
-            ).data(0, self.__edgesRole)
-            if self.logTree.topLevelItemCount() > 1 else
-            None
+            self.logTree.topLevelItem(self.logTree.indexOfTopLevelItem(itm) - 1).data(
+                0, self.__edgesRole
+            )
+            if self.logTree.topLevelItemCount() > 1
+            else None
         )
-        
-        icon = self.__generateIcon(column, color, edges, topedges,
-                                   QColor("blue"),
-                                   commitId == self.__projectRevision)
+
+        icon = self.__generateIcon(
+            column,
+            color,
+            edges,
+            topedges,
+            QColor("blue"),
+            commitId == self.__projectRevision,
+        )
         itm.setIcon(0, icon)
-        
+
         return itm
-    
+
     def __generateFileItem(self, action, path, copyfrom, additions, deletions):
         """
         Private method to generate a changed files tree entry.
-        
+
         @param action indicator for the change action ("A", "C", "D", "M",
             "R", "T", "U", "X")
         @param path path of the file in the repository (string)
@@ -759,174 +798,177 @@
             # includes confidence level
             confidence = int(action[1:])
             actionTxt = self.tr("{0} ({1}%)", "action, confidence").format(
-                self.flags[action[0]], confidence)
+                self.flags[action[0]], confidence
+            )
         else:
             actionTxt = self.flags[action]
-        itm = QTreeWidgetItem(self.filesTree, [
-            actionTxt,
-            path,
-            str(additions),
-            str(deletions),
-            copyfrom,
-        ])
-        
+        itm = QTreeWidgetItem(
+            self.filesTree,
+            [
+                actionTxt,
+                path,
+                str(additions),
+                str(deletions),
+                copyfrom,
+            ],
+        )
+
         itm.setTextAlignment(2, Qt.AlignmentFlag.AlignRight)
         itm.setTextAlignment(3, Qt.AlignmentFlag.AlignRight)
-        
+
         return itm
-    
+
     def __getLogEntries(self, skip=0, noEntries=0):
         """
         Private method to retrieve log entries from the repository.
-        
+
         @param skip number of log entries to skip (integer)
         @param noEntries number of entries to get (0 = default) (int)
         """
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Close).setEnabled(False)
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Cancel).setDefault(True)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
         QApplication.processEvents()
-        
+
         self.buf = []
         self.cancelled = False
         self.errors.clear()
         self.intercept = False
-        
+
         if noEntries == 0:
             noEntries = self.limitSpinBox.value()
-        
+
         args = self.vcs.initCommand("log")
-        args.append('--max-count={0}'.format(noEntries))
-        args.append('--numstat')
-        args.append('--abbrev={0}'.format(
-            self.vcs.getPlugin().getPreferences("CommitIdLength")))
+        args.append("--max-count={0}".format(noEntries))
+        args.append("--numstat")
+        args.append(
+            "--abbrev={0}".format(self.vcs.getPlugin().getPreferences("CommitIdLength"))
+        )
         if self.vcs.getPlugin().getPreferences("FindCopiesHarder"):
-            args.append('--find-copies-harder')
-        args.append('--format={0}'.format(self.__formatTemplate))
-        args.append('--full-history')
-        args.append('--all')
-        args.append('--skip={0}'.format(skip))
+            args.append("--find-copies-harder")
+        args.append("--format={0}".format(self.__formatTemplate))
+        args.append("--full-history")
+        args.append("--all")
+        args.append("--skip={0}".format(skip))
         if not self.projectMode:
             if not self.stopCheckBox.isChecked():
-                args.append('--follow')
-            args.append('--')
+                args.append("--follow")
+            args.append("--")
             args.append(self.__filename)
-        
+
         self.__process.kill()
-        
+
         self.__process.setWorkingDirectory(self.repodir)
-        
-        self.__process.start('git', args)
+
+        self.__process.start("git", args)
         procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
             self.inputGroup.setEnabled(False)
             self.inputGroup.hide()
             EricMessageBox.critical(
                 self,
-                self.tr('Process Generation Error'),
+                self.tr("Process Generation Error"),
                 self.tr(
-                    'The process {0} could not be started. '
-                    'Ensure, that it is in the search path.'
-                ).format('git'))
-    
+                    "The process {0} could not be started. "
+                    "Ensure, that it is in the search path."
+                ).format("git"),
+            )
+
     def start(self, fn, isFile=False, noEntries=0):
         """
         Public slot to start the git log command.
-        
+
         @param fn filename to show the log for (string)
         @param isFile flag indicating log for a file is to be shown
             (boolean)
         @param noEntries number of entries to get (0 = default) (int)
         """
         self.__isFile = isFile
-        
+
         self.sbsSelectLabel.clear()
-        
+
         self.errorGroup.hide()
         QApplication.processEvents()
-        
+
         self.__initData()
-        
+
         self.__filename = fn
         self.dname, self.fname = self.vcs.splitPath(fn)
-        
+
         # find the root of the repo
         self.repodir = self.dname
         while not os.path.isdir(os.path.join(self.repodir, self.vcs.adminDir)):
             self.repodir = os.path.dirname(self.repodir)
             if os.path.splitdrive(self.repodir)[1] == os.sep:
                 return
-        
-        self.projectMode = (self.fname == "." and self.dname == self.repodir)
+
+        self.projectMode = self.fname == "." and self.dname == self.repodir
         self.stopCheckBox.setDisabled(self.projectMode or self.fname == ".")
         self.activateWindow()
         self.raise_()
-        
+
         self.logTree.clear()
         self.__started = True
         self.__identifyProject()
         self.__getLogEntries(noEntries=noEntries)
-    
+
     def __procFinished(self, exitCode, exitStatus):
         """
         Private slot connected to the finished signal.
-        
+
         @param exitCode exit code of the process (integer)
         @param exitStatus exit status of the process (QProcess.ExitStatus)
         """
         self.__processBuffer()
         self.__finish()
-    
+
     def __finish(self):
         """
         Private slot called when the process finished or the user pressed
         the button.
         """
         if (
-            self.__process is not None and
-            self.__process.state() != QProcess.ProcessState.NotRunning
+            self.__process is not None
+            and self.__process.state() != QProcess.ProcessState.NotRunning
         ):
             self.__process.terminate()
             QTimer.singleShot(2000, self.__process.kill)
             self.__process.waitForFinished(3000)
-        
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Close).setEnabled(True)
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Close).setDefault(True)
-        
+
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
+
         self.inputGroup.setEnabled(False)
         self.inputGroup.hide()
         self.refreshButton.setEnabled(True)
-        
+
         while self.__finishCallbacks:
             self.__finishCallbacks.pop(0)()
-    
+
     def __processBufferItem(self, logEntry):
         """
         Private method to process a log entry.
-        
+
         @param logEntry dictionary as generated by __processBuffer
         """
         self.__generateLogItem(
-            logEntry["author"], logEntry["authordate"],
-            logEntry["committer"], logEntry["committerdate"],
-            logEntry["subject"], logEntry["body"],
-            logEntry["commit"], logEntry["changed_files"],
-            logEntry["parents"], logEntry["refnames"],
-            logEntry["authormail"], logEntry["committermail"]
+            logEntry["author"],
+            logEntry["authordate"],
+            logEntry["committer"],
+            logEntry["committerdate"],
+            logEntry["subject"],
+            logEntry["body"],
+            logEntry["commit"],
+            logEntry["changed_files"],
+            logEntry["parents"],
+            logEntry["refnames"],
+            logEntry["authormail"],
+            logEntry["committermail"],
         )
         for date in [logEntry["authordate"], logEntry["committerdate"]]:
             dt = QDate.fromString(date, Qt.DateFormat.ISODate)
-            if (
-                not self.__maxDate.isValid() and
-                not self.__minDate.isValid()
-            ):
+            if not self.__maxDate.isValid() and not self.__minDate.isValid():
                 self.__maxDate = dt
                 self.__minDate = dt
             else:
@@ -934,7 +976,7 @@
                     self.__maxDate = dt
                 if self.__minDate > dt:
                     self.__minDate = dt
-    
+
     def __processBuffer(self):
         """
         Private method to process the buffered output of the git log command.
@@ -942,7 +984,7 @@
         noEntries = 0
         logEntry = {"changed_files": []}
         descriptionBody = False
-        
+
         for line in self.buf:
             line = line.rstrip()
             if line == "recordstart":
@@ -980,46 +1022,63 @@
                             dst = head + middleDst.strip() + tail
                         else:
                             src, dst = changeInfo[2].split("=>")
-                        logEntry["changed_files"].append({
-                            "action": "C",
-                            "added": changeInfo[0].strip(),
-                            "deleted": changeInfo[1].strip(),
-                            "path": dst.strip(),
-                            "copyfrom": src.strip(),
-                        })
+                        logEntry["changed_files"].append(
+                            {
+                                "action": "C",
+                                "added": changeInfo[0].strip(),
+                                "deleted": changeInfo[1].strip(),
+                                "path": dst.strip(),
+                                "copyfrom": src.strip(),
+                            }
+                        )
                     else:
-                        logEntry["changed_files"].append({
-                            "action": "M",
-                            "added": changeInfo[0].strip(),
-                            "deleted": changeInfo[1].strip(),
-                            "path": changeInfo[2].strip(),
-                            "copyfrom": "",
-                        })
+                        logEntry["changed_files"].append(
+                            {
+                                "action": "M",
+                                "added": changeInfo[0].strip(),
+                                "deleted": changeInfo[1].strip(),
+                                "path": changeInfo[2].strip(),
+                                "copyfrom": "",
+                            }
+                        )
             else:
                 try:
                     key, value = line.split("|", 1)
                 except ValueError:
                     key = ""
                     value = line
-                if key in ("commit", "parents", "author", "authormail",
-                           "authordate", "committer", "committermail",
-                           "committerdate", "refnames", "subject"):
+                if key in (
+                    "commit",
+                    "parents",
+                    "author",
+                    "authormail",
+                    "authordate",
+                    "committer",
+                    "committermail",
+                    "committerdate",
+                    "refnames",
+                    "subject",
+                ):
                     logEntry[key] = value.strip()
         if len(logEntry) > 1:
             self.__processBufferItem(logEntry)
             noEntries += 1
-        
+
         self.__resizeColumnsLog()
-        
+
         if self.__started:
             if self.__selectedCommitIDs:
-                self.logTree.setCurrentItem(self.logTree.findItems(
-                    self.__selectedCommitIDs[0], Qt.MatchFlag.MatchExactly,
-                    self.CommitIdColumn)[0])
+                self.logTree.setCurrentItem(
+                    self.logTree.findItems(
+                        self.__selectedCommitIDs[0],
+                        Qt.MatchFlag.MatchExactly,
+                        self.CommitIdColumn,
+                    )[0]
+                )
             else:
                 self.logTree.setCurrentItem(self.logTree.topLevelItem(0))
             self.__started = False
-        
+
         self.__skipEntries += noEntries
         if noEntries < self.limitSpinBox.value() and not self.cancelled:
             self.nextButton.setEnabled(False)
@@ -1027,7 +1086,7 @@
         else:
             self.nextButton.setEnabled(True)
             self.limitSpinBox.setEnabled(True)
-        
+
         # update the log filters
         self.__filterLogsEnabled = False
         self.fromDate.setMinimumDate(self.__minDate)
@@ -1036,114 +1095,115 @@
         self.toDate.setMinimumDate(self.__minDate)
         self.toDate.setMaximumDate(self.__maxDate)
         self.toDate.setDate(self.__maxDate)
-        
+
         self.__filterLogsEnabled = True
         if self.__actionMode() == "filter":
             self.__filterLogs()
-        
+
         self.__updateToolMenuActions()
-        
+
         # restore selected items
         if self.__selectedCommitIDs:
             for commitID in self.__selectedCommitIDs:
                 items = self.logTree.findItems(
-                    commitID, Qt.MatchFlag.MatchExactly, self.CommitIdColumn)
+                    commitID, Qt.MatchFlag.MatchExactly, self.CommitIdColumn
+                )
                 if items:
                     items[0].setSelected(True)
             self.__selectedCommitIDs = []
-    
+
     def __readStdout(self):
         """
         Private slot to handle the readyReadStandardOutput signal.
-        
+
         It reads the output of the process and inserts it into a buffer.
         """
         self.__process.setReadChannel(QProcess.ProcessChannel.StandardOutput)
-        
+
         while self.__process.canReadLine():
-            line = str(self.__process.readLine(),
-                       Preferences.getSystem("IOEncoding"),
-                       'replace')
+            line = str(
+                self.__process.readLine(),
+                Preferences.getSystem("IOEncoding"),
+                "replace",
+            )
             self.buf.append(line)
-    
+
     def __readStderr(self):
         """
         Private slot to handle the readyReadStandardError signal.
-        
+
         It reads the error output of the process and inserts it into the
         error pane.
         """
         if self.__process is not None:
-            s = str(self.__process.readAllStandardError(),
-                    Preferences.getSystem("IOEncoding"),
-                    'replace')
+            s = str(
+                self.__process.readAllStandardError(),
+                Preferences.getSystem("IOEncoding"),
+                "replace",
+            )
             self.__showError(s)
-    
+
     def __showError(self, out):
         """
         Private slot to show some error.
-        
+
         @param out error to be shown (string)
         """
         self.errorGroup.show()
         self.errors.insertPlainText(out)
         self.errors.ensureCursorVisible()
-        
+
         # show input in case the process asked for some input
         self.inputGroup.setEnabled(True)
         self.inputGroup.show()
-    
+
     def on_buttonBox_clicked(self, button):
         """
         Private slot called by a button of the button box clicked.
-        
+
         @param button button that was clicked (QAbstractButton)
         """
-        if button == self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Close
-        ):
+        if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
             self.close()
-        elif button == self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Cancel
-        ):
+        elif button == self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel):
             self.cancelled = True
             self.__finish()
         elif button == self.refreshButton:
             self.on_refreshButton_clicked()
-    
+
     @pyqtSlot()
     def on_refreshButton_clicked(self):
         """
         Private slot to refresh the log.
         """
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Close).setEnabled(False)
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
-        self.buttonBox.button(
-            QDialogButtonBox.StandardButton.Cancel).setDefault(True)
-        
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setDefault(True)
+
         self.refreshButton.setEnabled(False)
-        
+
         # save the selected items commit IDs
         self.__selectedCommitIDs = []
         for item in self.logTree.selectedItems():
             self.__selectedCommitIDs.append(item.text(self.CommitIdColumn))
-        
-        self.start(self.__filename, isFile=self.__isFile,
-                   noEntries=self.logTree.topLevelItemCount())
-    
+
+        self.start(
+            self.__filename,
+            isFile=self.__isFile,
+            noEntries=self.logTree.topLevelItemCount(),
+        )
+
     def on_passwordCheckBox_toggled(self, isOn):
         """
         Private slot to handle the password checkbox toggled.
-        
+
         @param isOn flag indicating the status of the check box (boolean)
         """
         if isOn:
             self.input.setEchoMode(QLineEdit.EchoMode.Password)
         else:
             self.input.setEchoMode(QLineEdit.EchoMode.Normal)
-    
+
     @pyqtSlot()
     def on_sendButton_clicked(self):
         """
@@ -1151,7 +1211,7 @@
         """
         inputTxt = self.input.text()
         inputTxt += os.linesep
-        
+
         if self.passwordCheckBox.isChecked():
             self.errors.insertPlainText(os.linesep)
             self.errors.ensureCursorVisible()
@@ -1159,23 +1219,23 @@
             self.errors.insertPlainText(inputTxt)
             self.errors.ensureCursorVisible()
         self.errorGroup.show()
-        
+
         self.__process.write(strToQByteArray(inputTxt))
-        
+
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
-    
+
     def on_input_returnPressed(self):
         """
         Private slot to handle the press of the return key in the input field.
         """
         self.intercept = True
         self.on_sendButton_clicked()
-    
+
     def keyPressEvent(self, evt):
         """
         Protected slot to handle a key press event.
-        
+
         @param evt the key press event (QKeyEvent)
         """
         if self.intercept:
@@ -1183,11 +1243,11 @@
             evt.accept()
             return
         super().keyPressEvent(evt)
-    
+
     def __prepareFieldSearch(self):
         """
         Private slot to prepare the filed search data.
-        
+
         @return tuple of field index, search expression and flag indicating
             that the field index is a data role (integer, string, boolean)
         """
@@ -1203,8 +1263,7 @@
             fieldIndex = self.CommitIdColumn
             txt = self.rxEdit.text()
             if txt.startswith("^"):
-                searchRx = re.compile(r"^\s*{0}".format(txt[1:]),
-                                      re.IGNORECASE)
+                searchRx = re.compile(r"^\s*{0}".format(txt[1:]), re.IGNORECASE)
             else:
                 searchRx = re.compile(txt, re.IGNORECASE)
         elif txt == "file":
@@ -1215,9 +1274,9 @@
             fieldIndex = self.__subjectRole
             searchRx = re.compile(self.rxEdit.text(), re.IGNORECASE)
             indexIsRole = True
-        
+
         return fieldIndex, searchRx, indexIsRole
-    
+
     def __filterLogs(self):
         """
         Private method to filter the log entries.
@@ -1226,7 +1285,7 @@
             from_ = self.fromDate.date().toString("yyyy-MM-dd")
             to_ = self.toDate.date().addDays(1).toString("yyyy-MM-dd")
             fieldIndex, searchRx, indexIsRole = self.__prepareFieldSearch()
-            
+
             visibleItemCount = self.logTree.topLevelItemCount()
             currentItem = self.logTree.currentItem()
             for topIndex in range(self.logTree.topLevelItemCount()):
@@ -1235,8 +1294,8 @@
                     if fieldIndex == self.__changesRole:
                         changes = topItem.data(0, self.__changesRole)
                         txt = "\n".join(
-                            [c["path"] for c in changes] +
-                            [c["copyfrom"] for c in changes]
+                            [c["path"] for c in changes]
+                            + [c["copyfrom"] for c in changes]
                         )
                     else:
                         # Filter based on complete subject text
@@ -1244,9 +1303,9 @@
                 else:
                     txt = topItem.text(fieldIndex)
                 if (
-                    topItem.text(self.DateColumn) <= to_ and
-                    topItem.text(self.DateColumn) >= from_ and
-                    searchRx.search(txt) is not None
+                    topItem.text(self.DateColumn) <= to_
+                    and topItem.text(self.DateColumn) >= from_
+                    and searchRx.search(txt) is not None
                 ):
                     topItem.setHidden(False)
                     if topItem is currentItem:
@@ -1257,9 +1316,9 @@
                         self.filesTree.clear()
                     visibleItemCount -= 1
             self.logTree.header().setSectionHidden(
-                self.IconColumn,
-                visibleItemCount != self.logTree.topLevelItemCount())
-    
+                self.IconColumn, visibleItemCount != self.logTree.topLevelItemCount()
+            )
+
     def __updateSbsSelectLabel(self):
         """
         Private slot to update the enabled status of the diff buttons.
@@ -1275,24 +1334,30 @@
                     parentLinks = []
                     for index in range(len(parents)):
                         parentLinks.append(
-                            '<a href="sbsdiff:{0}_{1}">&nbsp;{2}&nbsp;</a>'
-                            .format(parents[index], commit2, index + 1))
+                            '<a href="sbsdiff:{0}_{1}">&nbsp;{2}&nbsp;</a>'.format(
+                                parents[index], commit2, index + 1
+                            )
+                        )
                     self.sbsSelectLabel.setText(
-                        self.tr('Side-by-Side Diff to Parent {0}').format(
-                            " ".join(parentLinks)))
+                        self.tr("Side-by-Side Diff to Parent {0}").format(
+                            " ".join(parentLinks)
+                        )
+                    )
             elif len(selectedItems) == 2:
                 commit2 = selectedItems[0].text(self.CommitIdColumn)
                 commit1 = selectedItems[1].text(self.CommitIdColumn)
                 index2 = self.logTree.indexOfTopLevelItem(selectedItems[0])
                 index1 = self.logTree.indexOfTopLevelItem(selectedItems[1])
-                
+
                 if index2 < index1:
                     # swap to always compare old to new
                     commit1, commit2 = commit2, commit1
-                self.sbsSelectLabel.setText(self.tr(
-                    '<a href="sbsdiff:{0}_{1}">Side-by-Side Compare</a>')
-                    .format(commit1, commit2))
-    
+                self.sbsSelectLabel.setText(
+                    self.tr(
+                        '<a href="sbsdiff:{0}_{1}">Side-by-Side Compare</a>'
+                    ).format(commit1, commit2)
+                )
+
     def __updateToolMenuActions(self):
         """
         Private slot to update the status of the tool menu actions and
@@ -1307,11 +1372,11 @@
             self.__branchAct.setEnabled(selectCount == 1)
             self.__branchSwitchAct.setEnabled(selectCount == 1)
             self.__shortlogAct.setEnabled(selectCount == 1)
-            
+
             self.actionsButton.setEnabled(True)
         else:
             self.actionsButton.setEnabled(False)
-    
+
     def __updateDetailsAndFiles(self):
         """
         Private slot to update the details and file changes panes.
@@ -1319,11 +1384,10 @@
         self.detailsEdit.clear()
         self.filesTree.clear()
         self.__diffUpdatesFiles = False
-        
+
         selectedItems = self.logTree.selectedItems()
         if len(selectedItems) == 1:
-            self.detailsEdit.setHtml(
-                self.__generateDetailsTableText(selectedItems[0]))
+            self.detailsEdit.setHtml(self.__generateDetailsTableText(selectedItems[0]))
             self.__updateFilesTree(self.filesTree, selectedItems[0])
             self.__resizeColumnsFiles()
             self.__resortFiles()
@@ -1337,7 +1401,8 @@
             if index1 > index2:
                 # Swap the entries
                 selectedItems[0], selectedItems[1] = (
-                    selectedItems[1], selectedItems[0]
+                    selectedItems[1],
+                    selectedItems[0],
                 )
             html = "{0}<hr/>{1}".format(
                 self.__generateDetailsTableText(selectedItems[0]),
@@ -1345,12 +1410,12 @@
             )
             self.detailsEdit.setHtml(html)
             # self.filesTree is updated by the diff
-    
+
     def __generateDetailsTableText(self, itm):
         """
         Private method to generate an HTML table with the details of the given
         changeset.
-        
+
         @param itm reference to the item the table should be based on
         @type QTreeWidgetItem
         @return HTML table containing details
@@ -1358,54 +1423,51 @@
         """
         if itm is not None:
             commitId = itm.text(self.CommitIdColumn)
-            
+
             parentLinks = []
             for parent in [str(x) for x in itm.data(0, self.__parentsRole)]:
                 parentLinks.append('<a href="rev:{0}">{0}</a>'.format(parent))
             if parentLinks:
-                parentsStr = self.__parentsTemplate.format(
-                    ", ".join(parentLinks))
+                parentsStr = self.__parentsTemplate.format(", ".join(parentLinks))
             else:
                 parentsStr = ""
-            
+
             childLinks = []
             for child in [str(x) for x in self.__childrenInfo[commitId]]:
                 childLinks.append('<a href="rev:{0}">{0}</a>'.format(child))
             if childLinks:
-                childrenStr = self.__childrenTemplate.format(
-                    ", ".join(childLinks))
+                childrenStr = self.__childrenTemplate.format(", ".join(childLinks))
             else:
                 childrenStr = ""
-            
+
             branchLinks = []
             for branch, branchHead in self.__getBranchesForCommit(commitId):
-                branchLinks.append('<a href="rev:{0}">{1}</a>'.format(
-                    branchHead, branch))
+                branchLinks.append(
+                    '<a href="rev:{0}">{1}</a>'.format(branchHead, branch)
+                )
             if branchLinks:
-                branchesStr = self.__branchesTemplate.format(
-                    ", ".join(branchLinks))
+                branchesStr = self.__branchesTemplate.format(", ".join(branchLinks))
             else:
                 branchesStr = ""
-            
+
             tagLinks = []
             for tag, tagCommit in self.__getTagsForCommit(commitId):
                 if tagCommit:
-                    tagLinks.append('<a href="rev:{0}">{1}</a>'.format(
-                        tagCommit, tag))
+                    tagLinks.append('<a href="rev:{0}">{1}</a>'.format(tagCommit, tag))
                 else:
                     tagLinks.append(tag)
             if tagLinks:
-                tagsStr = self.__tagsTemplate.format(
-                    ", ".join(tagLinks))
+                tagsStr = self.__tagsTemplate.format(", ".join(tagLinks))
             else:
                 tagsStr = ""
-            
+
             if itm.data(0, self.__messageRole):
                 messageStr = self.__mesageTemplate.format(
-                    "<br/>".join(itm.data(0, self.__messageRole)))
+                    "<br/>".join(itm.data(0, self.__messageRole))
+                )
             else:
                 messageStr = ""
-            
+
             html = self.__detailsTemplate.format(
                 commitId,
                 itm.text(self.DateColumn),
@@ -1420,13 +1482,13 @@
             )
         else:
             html = ""
-        
+
         return html
-    
+
     def __updateFilesTree(self, parent, itm):
         """
         Private method to update the files tree with changes of the given item.
-        
+
         @param parent parent for the items to be added
         @type QTreeWidget or QTreeWidgetItem
         @param itm reference to the item the update should be based on
@@ -1437,15 +1499,19 @@
             if len(changes) > 0:
                 for change in changes:
                     self.__generateFileItem(
-                        change["action"], change["path"], change["copyfrom"],
-                        change["added"], change["deleted"])
+                        change["action"],
+                        change["path"],
+                        change["copyfrom"],
+                        change["added"],
+                        change["deleted"],
+                    )
                 self.__resizeColumnsFiles()
                 self.__resortFiles()
-    
+
     def __getBranchesForCommit(self, commitId):
         """
         Private method to get all branches reachable from a commit ID.
-        
+
         @param commitId commit ID to get the branches for
         @type str
         @return list of tuples containing the branch name and the associated
@@ -1453,36 +1519,38 @@
         @rtype tuple of (str, str)
         """
         branches = []
-        
+
         args = self.vcs.initCommand("branch")
         args.append("--list")
         args.append("--verbose")
         args.append("--contains")
         args.append(commitId)
-        
+
         output = ""
         process = QProcess()
         process.setWorkingDirectory(self.repodir)
-        process.start('git', args)
+        process.start("git", args)
         procStarted = process.waitForStarted(5000)
         if procStarted:
             finished = process.waitForFinished(30000)
             if finished and process.exitCode() == 0:
-                output = str(process.readAllStandardOutput(),
-                             Preferences.getSystem("IOEncoding"),
-                             'replace')
-        
+                output = str(
+                    process.readAllStandardOutput(),
+                    Preferences.getSystem("IOEncoding"),
+                    "replace",
+                )
+
         if output:
             for line in output.splitlines():
                 name, commitId = line[2:].split(None, 2)[:2]
                 branches.append((name, commitId))
-        
+
         return branches
-    
+
     def __getTagsForCommit(self, commitId):
         """
         Private method to get all tags reachable from a commit ID.
-        
+
         @param commitId commit ID to get the tags for
         @type str
         @return list of tuples containing the tag name and the associated
@@ -1490,105 +1558,113 @@
         @rtype tuple of (str, str)
         """
         tags = []
-        
+
         args = self.vcs.initCommand("tag")
         args.append("--list")
         args.append("--contains")
         args.append(commitId)
-        
+
         output = ""
         process = QProcess()
         process.setWorkingDirectory(self.repodir)
-        process.start('git', args)
+        process.start("git", args)
         procStarted = process.waitForStarted(5000)
         if procStarted:
             finished = process.waitForFinished(30000)
             if finished and process.exitCode() == 0:
-                output = str(process.readAllStandardOutput(),
-                             Preferences.getSystem("IOEncoding"),
-                             'replace')
-        
+                output = str(
+                    process.readAllStandardOutput(),
+                    Preferences.getSystem("IOEncoding"),
+                    "replace",
+                )
+
         if output:
             tagNames = []
             for line in output.splitlines():
                 tagNames.append(line.strip())
-            
+
             # determine the commit IDs for the tags
             for tagName in tagNames:
                 commitId = self.__getCommitForTag(tagName)
                 tags.append((tagName, commitId))
-        
+
         return tags
-    
+
     def __getCommitForTag(self, tag):
         """
         Private method to get the commit id for a tag.
-        
+
         @param tag tag name (string)
         @return commit id shortened to 10 characters (string)
         """
         args = self.vcs.initCommand("show")
         args.append("--abbrev-commit")
-        args.append("--abbrev={0}".format(
-            self.vcs.getPlugin().getPreferences("CommitIdLength")))
+        args.append(
+            "--abbrev={0}".format(self.vcs.getPlugin().getPreferences("CommitIdLength"))
+        )
         args.append("--no-patch")
         args.append(tag)
-        
+
         output = ""
         process = QProcess()
         process.setWorkingDirectory(self.repodir)
-        process.start('git', args)
+        process.start("git", args)
         procStarted = process.waitForStarted(5000)
         if procStarted:
             finished = process.waitForFinished(30000)
             if finished and process.exitCode() == 0:
-                output = str(process.readAllStandardOutput(),
-                             Preferences.getSystem("IOEncoding"),
-                             'replace')
-        
+                output = str(
+                    process.readAllStandardOutput(),
+                    Preferences.getSystem("IOEncoding"),
+                    "replace",
+                )
+
         if output:
             for line in output.splitlines():
                 if line.startswith("commit "):
                     commitId = line.split()[1].strip()
                     return commitId
-        
+
         return ""
-    
+
     @pyqtSlot(QPoint)
     def on_logTree_customContextMenuRequested(self, pos):
         """
         Private slot to show the context menu of the log tree.
-        
+
         @param pos position of the mouse pointer (QPoint)
         """
         self.__logTreeMenu.popup(self.logTree.mapToGlobal(pos))
-    
+
     @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
     def on_logTree_currentItemChanged(self, current, previous):
         """
         Private slot called, when the current item of the log tree changes.
-        
+
         @param current reference to the new current item (QTreeWidgetItem)
         @param previous reference to the old current item (QTreeWidgetItem)
         """
         self.__updateToolMenuActions()
-        
+
         # Highlight the current entry using a bold font
         for col in range(self.logTree.columnCount()):
             current and current.setFont(col, self.__logTreeBoldFont)
             previous and previous.setFont(col, self.__logTreeNormalFont)
-        
+
         # set the state of the up and down buttons
         self.upButton.setEnabled(
-            current is not None and
-            self.logTree.indexOfTopLevelItem(current) > 0)
+            current is not None and self.logTree.indexOfTopLevelItem(current) > 0
+        )
         self.downButton.setEnabled(
-            current is not None and
-            len(current.data(0, self.__parentsRole)) > 0 and
-            (self.logTree.indexOfTopLevelItem(current) <
-                self.logTree.topLevelItemCount() - 1 or
-             self.nextButton.isEnabled()))
-    
+            current is not None
+            and len(current.data(0, self.__parentsRole)) > 0
+            and (
+                self.logTree.indexOfTopLevelItem(current)
+                < self.logTree.topLevelItemCount() - 1
+                or self.nextButton.isEnabled()
+            )
+        )
+
     @pyqtSlot()
     def on_logTree_itemSelectionChanged(self):
         """
@@ -1598,7 +1674,7 @@
         self.__updateSbsSelectLabel()
         self.__updateToolMenuActions()
         self.__generateDiffs()
-    
+
     @pyqtSlot()
     def on_upButton_clicked(self):
         """
@@ -1607,7 +1683,7 @@
         itm = self.logTree.itemAbove(self.logTree.currentItem())
         if itm:
             self.logTree.setCurrentItem(itm)
-    
+
     @pyqtSlot()
     def on_downButton_clicked(self):
         """
@@ -1621,7 +1697,7 @@
             if self.nextButton.isEnabled():
                 self.__addFinishCallback(self.on_downButton_clicked)
                 self.on_nextButton_clicked()
-    
+
     @pyqtSlot()
     def on_nextButton_clicked(self):
         """
@@ -1629,50 +1705,50 @@
         """
         if self.__skipEntries > 0 and self.nextButton.isEnabled():
             self.__getLogEntries(skip=self.__skipEntries)
-    
+
     @pyqtSlot(QDate)
     def on_fromDate_dateChanged(self, date):
         """
         Private slot called, when the from date changes.
-        
+
         @param date new date (QDate)
         """
         if self.__actionMode() == "filter":
             self.__filterLogs()
-    
+
     @pyqtSlot(QDate)
     def on_toDate_dateChanged(self, date):
         """
         Private slot called, when the from date changes.
-        
+
         @param date new date (QDate)
         """
         if self.__actionMode() == "filter":
             self.__filterLogs()
-    
+
     @pyqtSlot(int)
     def on_fieldCombo_activated(self, index):
         """
         Private slot called, when a new filter field is selected.
-        
+
         @param index index of the selected entry
         @type int
         """
         if self.__actionMode() == "filter":
             self.__filterLogs()
-    
+
     @pyqtSlot(str)
     def on_rxEdit_textChanged(self, txt):
         """
         Private slot called, when a filter expression is entered.
-        
+
         @param txt filter expression (string)
         """
         if self.__actionMode() == "filter":
             self.__filterLogs()
         elif self.__actionMode() == "find":
             self.__findItem(self.__findBackwards, interactive=True)
-    
+
     @pyqtSlot()
     def on_rxEdit_returnPressed(self):
         """
@@ -1680,59 +1756,58 @@
         """
         if self.__actionMode() == "find":
             self.__findItem(self.__findBackwards, interactive=True)
-    
+
     @pyqtSlot(bool)
     def on_stopCheckBox_clicked(self, checked):
         """
         Private slot called, when the stop on copy/move checkbox is clicked.
-        
+
         @param checked flag indicating the state of the check box (boolean)
         """
-        self.vcs.getPlugin().setPreferences("StopLogOnCopy",
-                                            self.stopCheckBox.isChecked())
+        self.vcs.getPlugin().setPreferences(
+            "StopLogOnCopy", self.stopCheckBox.isChecked()
+        )
         self.nextButton.setEnabled(True)
         self.limitSpinBox.setEnabled(True)
-    
+
     ##################################################################
     ## Tool button menu action methods below
     ##################################################################
-    
+
     @pyqtSlot()
     def __cherryActTriggered(self):
         """
         Private slot to handle the Copy Commits action.
         """
         commits = {}
-        
+
         for itm in self.logTree.selectedItems():
             index = self.logTree.indexOfTopLevelItem(itm)
             commits[index] = itm.text(self.CommitIdColumn)
-        
+
         if commits:
-            pfile = (
-                pathlib.Path(ericApp().getObject("Project").getProjectFile())
-            )
+            pfile = pathlib.Path(ericApp().getObject("Project").getProjectFile())
             lastModified = pfile.stat().st_mtime
             shouldReopen = (
                 self.vcs.gitCherryPick(
                     self.repodir,
-                    [commits[i] for i in sorted(commits.keys(), reverse=True)]
-                ) or
-                pfile.stat().st_mtime != lastModified
+                    [commits[i] for i in sorted(commits.keys(), reverse=True)],
+                )
+                or pfile.stat().st_mtime != lastModified
             )
             if shouldReopen:
                 res = EricMessageBox.yesNo(
                     None,
                     self.tr("Copy Changesets"),
-                    self.tr(
-                        """The project should be reread. Do this now?"""),
-                    yesDefault=True)
+                    self.tr("""The project should be reread. Do this now?"""),
+                    yesDefault=True,
+                )
                 if res:
                     ericApp().getObject("Project").reopenProject()
                     return
-            
+
             self.on_refreshButton_clicked()
-    
+
     @pyqtSlot()
     def __tagActTriggered(self):
         """
@@ -1745,7 +1820,7 @@
             res = self.vcs.vcsTag(self.repodir, revision=commit, tagName=tag)
             if res:
                 self.on_refreshButton_clicked()
-    
+
     @pyqtSlot()
     def __switchActTriggered(self):
         """
@@ -1755,8 +1830,9 @@
         if len(self.logTree.selectedItems()) == 1:
             itm = self.logTree.selectedItems()[0]
             commit = itm.text(self.CommitIdColumn)
-            branches = [b for b in itm.text(self.BranchColumn).split(", ")
-                        if "/" not in b]
+            branches = [
+                b for b in itm.text(self.BranchColumn).split(", ") if "/" not in b
+            ]
             if len(branches) == 1:
                 branch = branches[0]
             elif len(branches) > 1:
@@ -1765,7 +1841,9 @@
                     self.tr("Switch"),
                     self.tr("Select a branch"),
                     [""] + branches,
-                    0, False)
+                    0,
+                    False,
+                )
                 if not ok:
                     return
             else:
@@ -1774,27 +1852,25 @@
                 rev = branch
             else:
                 rev = commit
-            pfile = (
-                pathlib.Path(ericApp().getObject("Project").getProjectFile())
-            )
+            pfile = pathlib.Path(ericApp().getObject("Project").getProjectFile())
             lastModified = pfile.stat().st_mtime
             shouldReopen = (
-                self.vcs.vcsUpdate(self.repodir, revision=rev) or
-                pfile.stat().st_mtime != lastModified
+                self.vcs.vcsUpdate(self.repodir, revision=rev)
+                or pfile.stat().st_mtime != lastModified
             )
             if shouldReopen:
                 res = EricMessageBox.yesNo(
                     None,
                     self.tr("Switch"),
-                    self.tr(
-                        """The project should be reread. Do this now?"""),
-                    yesDefault=True)
+                    self.tr("""The project should be reread. Do this now?"""),
+                    yesDefault=True,
+                )
                 if res:
                     ericApp().getObject("Project").reopenProject()
                     return
-            
+
             self.on_refreshButton_clicked()
-    
+
     @pyqtSlot()
     def __branchActTriggered(self):
         """
@@ -1802,10 +1878,12 @@
         """
         if len(self.logTree.selectedItems()) == 1:
             from .GitBranchDialog import GitBranchDialog
+
             itm = self.logTree.selectedItems()[0]
             commit = itm.text(self.CommitIdColumn)
-            branches = [b for b in itm.text(self.BranchColumn).split(", ")
-                        if "/" not in b]
+            branches = [
+                b for b in itm.text(self.BranchColumn).split(", ") if "/" not in b
+            ]
             if len(branches) == 1:
                 branch = branches[0]
             elif len(branches) > 1:
@@ -1814,17 +1892,22 @@
                     self.tr("Branch"),
                     self.tr("Select a default branch"),
                     [""] + branches,
-                    0, False)
+                    0,
+                    False,
+                )
                 if not ok:
                     return
             else:
                 branch = ""
             res = self.vcs.gitBranch(
-                self.repodir, revision=commit, branchName=branch,
-                branchOp=GitBranchDialog.CreateBranch)
+                self.repodir,
+                revision=commit,
+                branchName=branch,
+                branchOp=GitBranchDialog.CreateBranch,
+            )
             if res:
                 self.on_refreshButton_clicked()
-    
+
     @pyqtSlot()
     def __branchSwitchActTriggered(self):
         """
@@ -1833,10 +1916,12 @@
         """
         if len(self.logTree.selectedItems()) == 1:
             from .GitBranchDialog import GitBranchDialog
+
             itm = self.logTree.selectedItems()[0]
             commit = itm.text(self.CommitIdColumn)
-            branches = [b for b in itm.text(self.BranchColumn).split(", ")
-                        if "/" not in b]
+            branches = [
+                b for b in itm.text(self.BranchColumn).split(", ") if "/" not in b
+            ]
             if len(branches) == 1:
                 branch = branches[0]
             elif len(branches) > 1:
@@ -1845,33 +1930,36 @@
                     self.tr("Branch & Switch"),
                     self.tr("Select a default branch"),
                     [""] + branches,
-                    0, False)
+                    0,
+                    False,
+                )
                 if not ok:
                     return
             else:
                 branch = ""
-            pfile = (
-                pathlib.Path(ericApp().getObject("Project").getProjectFile())
-            )
+            pfile = pathlib.Path(ericApp().getObject("Project").getProjectFile())
             lastModified = pfile.stat().st_mtime
             res, shouldReopen = self.vcs.gitBranch(
-                self.repodir, revision=commit, branchName=branch,
-                branchOp=GitBranchDialog.CreateSwitchBranch)
+                self.repodir,
+                revision=commit,
+                branchName=branch,
+                branchOp=GitBranchDialog.CreateSwitchBranch,
+            )
             shouldReopen |= pfile.stat().st_mtime != lastModified
             if res:
                 if shouldReopen:
                     res = EricMessageBox.yesNo(
                         None,
                         self.tr("Switch"),
-                        self.tr(
-                            """The project should be reread. Do this now?"""),
-                        yesDefault=True)
+                        self.tr("""The project should be reread. Do this now?"""),
+                        yesDefault=True,
+                    )
                     if res:
                         ericApp().getObject("Project").reopenProject()
                         return
-                
+
                 self.on_refreshButton_clicked()
-    
+
     @pyqtSlot()
     def __shortlogActTriggered(self):
         """
@@ -1881,8 +1969,9 @@
             itm = self.logTree.selectedItems()[0]
             commit = itm.text(self.CommitIdColumn)
             branch = itm.text(self.BranchColumn).split(", ", 1)[0]
-            branches = [b for b in itm.text(self.BranchColumn).split(", ")
-                        if "/" not in b]
+            branches = [
+                b for b in itm.text(self.BranchColumn).split(", ") if "/" not in b
+            ]
             if len(branches) == 1:
                 branch = branches[0]
             elif len(branches) > 1:
@@ -1891,7 +1980,9 @@
                     self.tr("Show Short Log"),
                     self.tr("Select a branch"),
                     [""] + branches,
-                    0, False)
+                    0,
+                    False,
+                )
                 if not ok:
                     return
             else:
@@ -1901,143 +1992,141 @@
             else:
                 rev = commit
             self.vcs.gitShortlog(self.repodir, commit=rev)
-    
+
     @pyqtSlot()
     def __describeActTriggered(self):
         """
         Private slot to show the most recent tag reachable from a commit.
         """
         commits = []
-        
+
         for itm in self.logTree.selectedItems():
             commits.append(itm.text(self.CommitIdColumn))
-        
+
         if commits:
             self.vcs.gitDescribe(self.repodir, commits)
-    
+
     ##################################################################
     ## Log context menu action methods below
     ##################################################################
-    
+
     @pyqtSlot(bool)
     def __showCommitterColumns(self, on):
         """
         Private slot to show/hide the committer columns.
-        
+
         @param on flag indicating the selection state (boolean)
         """
         self.logTree.setColumnHidden(self.CommitterColumn, not on)
         self.logTree.setColumnHidden(self.CommitDateColumn, not on)
         self.vcs.getPlugin().setPreferences("ShowCommitterColumns", on)
         self.__resizeColumnsLog()
-    
+
     @pyqtSlot(bool)
     def __showAuthorColumns(self, on):
         """
         Private slot to show/hide the committer columns.
-        
+
         @param on flag indicating the selection state (boolean)
         """
         self.logTree.setColumnHidden(self.AuthorColumn, not on)
         self.logTree.setColumnHidden(self.DateColumn, not on)
         self.vcs.getPlugin().setPreferences("ShowAuthorColumns", on)
         self.__resizeColumnsLog()
-    
+
     @pyqtSlot(bool)
     def __showCommitIdColumn(self, on):
         """
         Private slot to show/hide the commit ID column.
-        
+
         @param on flag indicating the selection state (boolean)
         """
         self.logTree.setColumnHidden(self.CommitIdColumn, not on)
         self.vcs.getPlugin().setPreferences("ShowCommitIdColumn", on)
         self.__resizeColumnsLog()
-    
+
     @pyqtSlot(bool)
     def __showBranchesColumn(self, on):
         """
         Private slot to show/hide the branches column.
-        
+
         @param on flag indicating the selection state (boolean)
         """
         self.logTree.setColumnHidden(self.BranchColumn, not on)
         self.vcs.getPlugin().setPreferences("ShowBranchesColumn", on)
         self.__resizeColumnsLog()
-    
+
     @pyqtSlot(bool)
     def __showTagsColumn(self, on):
         """
         Private slot to show/hide the tags column.
-        
+
         @param on flag indicating the selection state (boolean)
         """
         self.logTree.setColumnHidden(self.TagsColumn, not on)
         self.vcs.getPlugin().setPreferences("ShowTagsColumn", on)
         self.__resizeColumnsLog()
-    
+
     ##################################################################
     ## Search and filter methods below
     ##################################################################
-    
+
     def __actionMode(self):
         """
         Private method to get the selected action mode.
-        
+
         @return selected action mode (string, one of filter or find)
         """
-        return self.modeComboBox.itemData(
-            self.modeComboBox.currentIndex())
-    
+        return self.modeComboBox.itemData(self.modeComboBox.currentIndex())
+
     @pyqtSlot(int)
     def on_modeComboBox_currentIndexChanged(self, index):
         """
         Private slot to react on mode changes.
-        
+
         @param index index of the selected entry (integer)
         """
         mode = self.modeComboBox.itemData(index)
         findMode = mode == "find"
         filterMode = mode == "filter"
-        
+
         self.fromDate.setEnabled(filterMode)
         self.toDate.setEnabled(filterMode)
         self.findPrevButton.setVisible(findMode)
         self.findNextButton.setVisible(findMode)
-        
+
         if findMode:
             for topIndex in range(self.logTree.topLevelItemCount()):
                 self.logTree.topLevelItem(topIndex).setHidden(False)
             self.logTree.header().setSectionHidden(self.IconColumn, False)
         elif filterMode:
             self.__filterLogs()
-    
+
     @pyqtSlot()
     def on_findPrevButton_clicked(self):
         """
         Private slot to find the previous item matching the entered criteria.
         """
         self.__findItem(True)
-    
+
     @pyqtSlot()
     def on_findNextButton_clicked(self):
         """
         Private slot to find the next item matching the entered criteria.
         """
         self.__findItem(False)
-    
+
     def __findItem(self, backwards=False, interactive=False):
         """
         Private slot to find an item matching the entered criteria.
-        
+
         @param backwards flag indicating to search backwards (boolean)
         @param interactive flag indicating an interactive search (boolean)
         """
         self.__findBackwards = backwards
-        
+
         fieldIndex, searchRx, indexIsRole = self.__prepareFieldSearch()
-        currentIndex = self.logTree.indexOfTopLevelItem(
-            self.logTree.currentItem())
+        currentIndex = self.logTree.indexOfTopLevelItem(self.logTree.currentItem())
         if backwards:
             if interactive:
                 indexes = range(currentIndex, -1, -1)
@@ -2047,17 +2136,15 @@
             if interactive:
                 indexes = range(currentIndex, self.logTree.topLevelItemCount())
             else:
-                indexes = range(currentIndex + 1,
-                                self.logTree.topLevelItemCount())
-        
+                indexes = range(currentIndex + 1, self.logTree.topLevelItemCount())
+
         for index in indexes:
             topItem = self.logTree.topLevelItem(index)
             if indexIsRole:
                 if fieldIndex == self.__changesRole:
                     changes = topItem.data(0, self.__changesRole)
                     txt = "\n".join(
-                        [c["path"] for c in changes] +
-                        [c["copyfrom"] for c in changes]
+                        [c["path"] for c in changes] + [c["copyfrom"] for c in changes]
                     )
                 else:
                     # Filter based on complete subject text
@@ -2071,17 +2158,18 @@
             EricMessageBox.information(
                 self,
                 self.tr("Find Commit"),
-                self.tr("""'{0}' was not found.""").format(self.rxEdit.text()))
-    
+                self.tr("""'{0}' was not found.""").format(self.rxEdit.text()),
+            )
+
     ##################################################################
     ## Commit navigation methods below
     ##################################################################
-    
+
     def __commitIdClicked(self, url):
         """
         Private slot to handle the anchorClicked signal of the changeset
         details pane.
-        
+
         @param url URL that was clicked
         @type QUrl
         """
@@ -2089,7 +2177,8 @@
             # a commit ID was clicked, show the respective item
             commitId = url.path()
             items = self.logTree.findItems(
-                commitId, Qt.MatchFlag.MatchStartsWith, self.CommitIdColumn)
+                commitId, Qt.MatchFlag.MatchStartsWith, self.CommitIdColumn
+            )
             if items:
                 itm = items[0]
                 if itm.isHidden():
@@ -2098,18 +2187,17 @@
             else:
                 # load the next batch and try again
                 if self.nextButton.isEnabled():
-                    self.__addFinishCallback(
-                        lambda: self.__commitIdClicked(url))
+                    self.__addFinishCallback(lambda: self.__commitIdClicked(url))
                     self.on_nextButton_clicked()
-    
+
     ###########################################################################
     ## Diff handling methods below
     ###########################################################################
-    
+
     def __generateDiffs(self, parent=1):
         """
         Private slot to generate diff outputs for the selected item.
-        
+
         @param parent number of parent to diff against
         @type int
         """
@@ -2118,7 +2206,7 @@
         self.diffSelectLabel.clear()
         with contextlib.suppress(AttributeError):
             self.diffHighlighter.regenerateRules()
-        
+
         selectedItems = self.logTree.selectedItems()
         if len(selectedItems) == 1:
             currentItem = selectedItems[0]
@@ -2126,11 +2214,12 @@
             parents = currentItem.data(0, self.__parentsRole)
             if len(parents) >= parent:
                 self.diffLabel.setText(
-                    self.tr("Differences to Parent {0}").format(parent))
+                    self.tr("Differences to Parent {0}").format(parent)
+                )
                 commit1 = parents[parent - 1]
-                
+
                 self.__diffGenerator.start(self.__filename, [commit1, commit2])
-            
+
             if len(parents) > 1:
                 parentLinks = []
                 for index in range(1, len(parents) + 1):
@@ -2138,38 +2227,38 @@
                         parentLinks.append("&nbsp;{0}&nbsp;".format(index))
                     else:
                         parentLinks.append(
-                            '<a href="diff:{0}">&nbsp;{0}&nbsp;</a>'
-                            .format(index))
+                            '<a href="diff:{0}">&nbsp;{0}&nbsp;</a>'.format(index)
+                        )
                     self.diffSelectLabel.setText(
-                        self.tr('Diff to Parent {0}')
-                        .format(" ".join(parentLinks)))
+                        self.tr("Diff to Parent {0}").format(" ".join(parentLinks))
+                    )
         elif len(selectedItems) == 2:
             commit2 = selectedItems[0].text(self.CommitIdColumn)
             commit1 = selectedItems[1].text(self.CommitIdColumn)
             index2 = self.logTree.indexOfTopLevelItem(selectedItems[0])
             index1 = self.logTree.indexOfTopLevelItem(selectedItems[1])
-            
+
             if index2 < index1:
                 # swap to always compare old to new
                 commit1, commit2 = commit2, commit1
-            
+
             self.__diffGenerator.start(self.__filename, [commit1, commit2])
-    
+
     def __generatorFinished(self):
         """
         Private slot connected to the finished signal of the diff generator.
         """
         diff, _, errors, fileSeparators = self.__diffGenerator.getResult()
-        
+
         if diff:
             self.diffEdit.setPlainText("".join(diff))
         elif errors:
             self.diffEdit.setPlainText("".join(errors))
         else:
-            self.diffEdit.setPlainText(self.tr('There is no difference.'))
-        
+            self.diffEdit.setPlainText(self.tr("There is no difference."))
+
         self.saveLabel.setVisible(bool(diff))
-        
+
         fileSeparators = self.__mergeFileSeparators(fileSeparators)
         if self.__diffUpdatesFiles:
             for oldFileName, newFileName, lineNumber, _ in fileSeparators:
@@ -2179,7 +2268,8 @@
                     item = QTreeWidgetItem(self.filesTree, ["", newFileName])
                 else:
                     item = QTreeWidgetItem(
-                        self.filesTree, ["", newFileName, "", "", oldFileName])
+                        self.filesTree, ["", newFileName, "", "", oldFileName]
+                    )
                 item.setData(0, self.__diffFileLineRole, lineNumber)
             self.__resizeColumnsFiles()
             self.__resortFiles()
@@ -2188,20 +2278,20 @@
                 for fileName in (oldFileName, newFileName):
                     if fileName != "/dev/null":
                         items = self.filesTree.findItems(
-                            fileName, Qt.MatchFlag.MatchExactly, 1)
+                            fileName, Qt.MatchFlag.MatchExactly, 1
+                        )
                         for item in items:
-                            item.setData(0, self.__diffFileLineRole,
-                                         lineNumber)
-        
+                            item.setData(0, self.__diffFileLineRole, lineNumber)
+
         tc = self.diffEdit.textCursor()
         tc.movePosition(QTextCursor.MoveOperation.Start)
         self.diffEdit.setTextCursor(tc)
         self.diffEdit.ensureCursorVisible()
-    
+
     def __mergeFileSeparators(self, fileSeparators):
         """
         Private method to merge the file separator entries.
-        
+
         @param fileSeparators list of file separator entries to be merged
         @return merged list of file separator entries
         """
@@ -2215,12 +2305,12 @@
                 if pos2 != -2:
                     separators[(oldFile, newFile)][3] = pos2
         return list(separators.values())
-    
+
     @pyqtSlot(QTreeWidgetItem, QTreeWidgetItem)
     def on_filesTree_currentItemChanged(self, current, previous):
         """
         Private slot called, when the current item of the files tree changes.
-        
+
         @param current reference to the new current item (QTreeWidgetItem)
         @param previous reference to the old current item (QTreeWidgetItem)
         """
@@ -2243,20 +2333,23 @@
                     tc.movePosition(QTextCursor.MoveOperation.End)
                     self.diffEdit.setTextCursor(tc)
                     self.diffEdit.ensureCursorVisible()
-                    
+
                     # step 2: move cursor to desired line
                     tc = self.diffEdit.textCursor()
                     delta = tc.blockNumber() - para
-                    tc.movePosition(QTextCursor.MoveOperation.PreviousBlock,
-                                    QTextCursor.MoveMode.MoveAnchor, delta)
+                    tc.movePosition(
+                        QTextCursor.MoveOperation.PreviousBlock,
+                        QTextCursor.MoveMode.MoveAnchor,
+                        delta,
+                    )
                     self.diffEdit.setTextCursor(tc)
                     self.diffEdit.ensureCursorVisible()
-    
+
     @pyqtSlot(str)
     def on_diffSelectLabel_linkActivated(self, link):
         """
         Private slot to handle the selection of a diff target.
-        
+
         @param link activated link
         @type str
         """
@@ -2266,43 +2359,44 @@
                 with contextlib.suppress(ValueError):
                     parent = int(parent)
                     self.__generateDiffs(parent)
-    
+
     @pyqtSlot(str)
     def on_saveLabel_linkActivated(self, link):
         """
         Private slot to handle the selection of the save link.
-        
+
         @param link activated link
         @type str
         """
         if ":" not in link:
             return
-        
+
         scheme, rest = link.split(":", 1)
         if scheme != "save" or rest != "me":
             return
-        
+
         if self.projectMode:
             fname = self.vcs.splitPath(self.__filename)[0]
             fname += "/{0}.diff".format(os.path.split(fname)[-1])
         else:
             dname, fname = self.vcs.splitPath(self.__filename)
-            if fname != '.':
+            if fname != ".":
                 fname = "{0}.diff".format(self.__filename)
             else:
                 fname = dname
-        
+
         fname, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
             self,
             self.tr("Save Diff"),
             fname,
             self.tr("Patch Files (*.diff)"),
             None,
-            EricFileDialog.DontConfirmOverwrite)
-        
+            EricFileDialog.DontConfirmOverwrite,
+        )
+
         if not fname:
             return  # user aborted
-        
+
         fpath = pathlib.Path(fname)
         if not fpath.suffix:
             ex = selectedFilter.split("(*")[1].split(")")[0]
@@ -2312,12 +2406,14 @@
             res = EricMessageBox.yesNo(
                 self,
                 self.tr("Save Diff"),
-                self.tr("<p>The patch file <b>{0}</b> already exists."
-                        " Overwrite it?</p>").format(fpath),
-                icon=EricMessageBox.Warning)
+                self.tr(
+                    "<p>The patch file <b>{0}</b> already exists." " Overwrite it?</p>"
+                ).format(fpath),
+                icon=EricMessageBox.Warning,
+            )
             if not res:
                 return
-        
+
         eol = ericApp().getObject("Project").getEolString()
         try:
             with fpath.open("w", encoding="utf-8", newline="") as f:
@@ -2325,17 +2421,19 @@
                 f.write(eol)
         except OSError as why:
             EricMessageBox.critical(
-                self, self.tr('Save Diff'),
+                self,
+                self.tr("Save Diff"),
                 self.tr(
-                    '<p>The patch file <b>{0}</b> could not be saved.'
-                    '<br>Reason: {1}</p>')
-                .format(fpath, str(why)))
-    
+                    "<p>The patch file <b>{0}</b> could not be saved."
+                    "<br>Reason: {1}</p>"
+                ).format(fpath, str(why)),
+            )
+
     @pyqtSlot(str)
     def on_sbsSelectLabel_linkActivated(self, link):
         """
         Private slot to handle selection of a side-by-side link.
-        
+
         @param link text of the selected link
         @type str
         """
@@ -2343,5 +2441,4 @@
             scheme, path = link.split(":", 1)
             if scheme == "sbsdiff" and "_" in path:
                 commit1, commit2 = path.split("_", 1)
-                self.vcs.vcsSbsDiff(self.__filename,
-                                    revisions=(commit1, commit2))
+                self.vcs.vcsSbsDiff(self.__filename, revisions=(commit1, commit2))

eric ide

mercurial