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

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/Plugins/VcsPlugins/vcsGit/GitStashBrowserDialog.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/Plugins/VcsPlugins/vcsGit/GitStashBrowserDialog.py	Wed Jul 13 14:55:47 2022 +0200
@@ -11,8 +11,14 @@
 
 from PyQt6.QtCore import pyqtSlot, Qt, QPoint, QProcess, QTimer
 from PyQt6.QtWidgets import (
-    QWidget, QDialogButtonBox, QTreeWidgetItem, QAbstractButton, QMenu,
-    QHeaderView, QApplication, QLineEdit
+    QWidget,
+    QDialogButtonBox,
+    QTreeWidgetItem,
+    QAbstractButton,
+    QMenu,
+    QHeaderView,
+    QApplication,
+    QLineEdit,
 )
 
 from EricWidgets import EricMessageBox
@@ -28,89 +34,91 @@
     """
     Class implementing a dialog to show the stashes.
     """
+
     NameColumn = 0
     DateColumn = 1
     MessageColumn = 2
-    
+
     Separator = "@@||@@"
-    
+
     TotalStatisticsRole = Qt.ItemDataRole.UserRole
     FileStatisticsRole = Qt.ItemDataRole.UserRole + 1
-    
+
     def __init__(self, vcs, parent=None):
         """
         Constructor
-        
+
         @param vcs reference to the vcs object
         @param parent reference to the parent widget (QWidget)
         """
         super().__init__(parent)
         self.setupUi(self)
-        
-        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.__position = QPoint()
-        
+
         self.__fileStatisticsRole = Qt.ItemDataRole.UserRole
         self.__totalStatisticsRole = Qt.ItemDataRole.UserRole + 1
-        
-        self.stashList.header().setSortIndicator(
-            0, Qt.SortOrder.AscendingOrder)
-        
+
+        self.stashList.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder)
+
         self.refreshButton = self.buttonBox.addButton(
-            self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole)
-        self.refreshButton.setToolTip(
-            self.tr("Press to refresh the list of stashes"))
+            self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole
+        )
+        self.refreshButton.setToolTip(self.tr("Press to refresh the list of stashes"))
         self.refreshButton.setEnabled(False)
-        
+
         self.vcs = vcs
         self.__resetUI()
-        
+
         self.__ioEncoding = Preferences.getSystem("IOEncoding")
-        
+
         self.__process = EricOverrideCursorProcess()
         self.__process.finished.connect(self.__procFinished)
         self.__process.readyReadStandardOutput.connect(self.__readStdout)
         self.__process.readyReadStandardError.connect(self.__readStderr)
-        
+
         self.__contextMenu = QMenu()
         self.__differencesAct = self.__contextMenu.addAction(
-            self.tr("Show"), self.__showPatch)
+            self.tr("Show"), self.__showPatch
+        )
         self.__contextMenu.addSeparator()
         self.__applyAct = self.__contextMenu.addAction(
-            self.tr("Restore && Keep"), self.__apply)
+            self.tr("Restore && Keep"), self.__apply
+        )
         self.__popAct = self.__contextMenu.addAction(
-            self.tr("Restore && Delete"), self.__pop)
+            self.tr("Restore && Delete"), self.__pop
+        )
         self.__contextMenu.addSeparator()
         self.__branchAct = self.__contextMenu.addAction(
-            self.tr("Create Branch"), self.__branch)
+            self.tr("Create Branch"), self.__branch
+        )
         self.__contextMenu.addSeparator()
-        self.__dropAct = self.__contextMenu.addAction(
-            self.tr("Delete"), self.__drop)
+        self.__dropAct = self.__contextMenu.addAction(self.tr("Delete"), self.__drop)
         self.__clearAct = self.__contextMenu.addAction(
-            self.tr("Delete All"), self.__clear)
-    
+            self.tr("Delete All"), self.__clear
+        )
+
     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.__position = self.pos()
-        
+
         e.accept()
-    
+
     def show(self):
         """
         Public slot to show the dialog.
@@ -118,135 +126,129 @@
         if not self.__position.isNull():
             self.move(self.__position)
         self.__resetUI()
-        
+
         super().show()
-    
+
     def __resetUI(self):
         """
         Private method to reset the user interface.
         """
         self.stashList.clear()
-    
+
     def __resizeColumnsStashes(self):
         """
         Private method to resize the shelve list columns.
         """
-        self.stashList.header().resizeSections(
-            QHeaderView.ResizeMode.ResizeToContents)
+        self.stashList.header().resizeSections(QHeaderView.ResizeMode.ResizeToContents)
         self.stashList.header().setStretchLastSection(True)
-    
+
     def __generateStashEntry(self, name, date, message):
         """
         Private method to generate the stash items.
-        
+
         @param name name of the stash (string)
         @param date date the stash was created (string)
         @param message stash message (string)
         """
         QTreeWidgetItem(self.stashList, [name, date, message])
-    
+
     def __getStashEntries(self):
         """
         Private method to retrieve the list of stashes.
         """
-        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.inputGroup.setEnabled(True)
         self.inputGroup.show()
         self.refreshButton.setEnabled(False)
-        
+
         self.buf = []
         self.errors.clear()
         self.intercept = False
-        
+
         args = self.vcs.initCommand("stash")
         args.append("list")
         args.append("--format=format:%gd{0}%ai{0}%gs%n".format(self.Separator))
-        
+
         self.__process.kill()
-        
+
         self.__process.setWorkingDirectory(self.repodir)
-        
+
         self.inputGroup.setEnabled(True)
         self.inputGroup.show()
-        
-        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, projectDir):
         """
         Public slot to start the git stash command.
-        
+
         @param projectDir name of the project directory (string)
         """
         self.errorGroup.hide()
         QApplication.processEvents()
-        
+
         self.__projectDir = projectDir
-        
+
         # find the root of the repo
         self.repodir = self.__projectDir
         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.activateWindow()
         self.raise_()
-        
+
         self.stashList.clear()
         self.__started = True
         self.__getStashEntries()
-    
+
     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)
-    
+
     def __processBuffer(self):
         """
         Private method to process the buffered output of the git stash command.
@@ -255,65 +257,59 @@
             name, date, message = line.split(self.Separator)
             date = date.strip().rsplit(":", 1)[0]
             self.__generateStashEntry(name, date, message.strip())
-        
+
         self.__resizeColumnsStashes()
-        
+
         if self.__started:
             self.stashList.setCurrentItem(self.stashList.topLevelItem(0))
             self.__started = False
-    
+
     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(), self.__ioEncoding,
-                       'replace').strip()
+            line = str(self.__process.readLine(), self.__ioEncoding, "replace").strip()
             if line:
                 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(),
-                    self.__ioEncoding, 'replace')
+            s = str(self.__process.readAllStandardError(), self.__ioEncoding, "replace")
             self.errorGroup.show()
             self.errors.insertPlainText(s)
             self.errors.ensureCursorVisible()
-    
+
     @pyqtSlot(QAbstractButton)
     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(QTreeWidgetItem, QTreeWidgetItem)
     def on_stashList_currentItemChanged(self, current, previous):
         """
         Private slot called, when the current item of the stash list changes.
-        
+
         @param current reference to the new current item (QTreeWidgetItem)
         @param previous reference to the old current item (QTreeWidgetItem)
         """
@@ -321,71 +317,86 @@
         self.filesLabel.setText("")
         self.insertionsLabel.setText("")
         self.deletionsLabel.setText("")
-        
+
         if current:
             if current.data(0, self.TotalStatisticsRole) is None:
                 args = self.vcs.initCommand("stash")
                 args.append("show")
-                args.append('--numstat')
+                args.append("--numstat")
                 args.append(current.text(self.NameColumn))
-                
+
                 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:
                     totals = {"files": 0, "additions": 0, "deletions": 0}
                     fileData = []
                     for line in output.splitlines():
-                        additions, deletions, name = (
-                            line.strip().split(None, 2)
-                        )
+                        additions, deletions, name = line.strip().split(None, 2)
                         totals["files"] += 1
                         if additions != "-":
                             totals["additions"] += int(additions)
                         if deletions != "-":
                             totals["deletions"] += int(deletions)
-                        fileData.append({
-                            "file": name,
-                            "total": ("-" if additions == "-" else
-                                      str(int(additions) + int(deletions))),
-                            "added": additions,
-                            "deleted": deletions
-                        })
+                        fileData.append(
+                            {
+                                "file": name,
+                                "total": (
+                                    "-"
+                                    if additions == "-"
+                                    else str(int(additions) + int(deletions))
+                                ),
+                                "added": additions,
+                                "deleted": deletions,
+                            }
+                        )
                     current.setData(0, self.TotalStatisticsRole, totals)
                     current.setData(0, self.FileStatisticsRole, fileData)
                 else:
                     return
-            
+
             for dataDict in current.data(0, self.FileStatisticsRole):
-                QTreeWidgetItem(self.statisticsList, [
-                    dataDict["file"], dataDict["total"],
-                    dataDict["added"], dataDict["deleted"]])
+                QTreeWidgetItem(
+                    self.statisticsList,
+                    [
+                        dataDict["file"],
+                        dataDict["total"],
+                        dataDict["added"],
+                        dataDict["deleted"],
+                    ],
+                )
             self.statisticsList.header().resizeSections(
-                QHeaderView.ResizeMode.ResizeToContents)
+                QHeaderView.ResizeMode.ResizeToContents
+            )
             self.statisticsList.header().setStretchLastSection(True)
-            
+
             totals = current.data(0, self.TotalStatisticsRole)
             self.filesLabel.setText(
-                self.tr("%n file(s) changed", None, totals["files"]))
+                self.tr("%n file(s) changed", None, totals["files"])
+            )
             self.insertionsLabel.setText(
-                self.tr("%n line(s) inserted", None, int(totals["additions"])))
+                self.tr("%n line(s) inserted", None, int(totals["additions"]))
+            )
             self.deletionsLabel.setText(
-                self.tr("%n line(s) deleted", None, int(totals["deletions"])))
-    
+                self.tr("%n line(s) deleted", None, int(totals["deletions"]))
+            )
+
     @pyqtSlot(QPoint)
     def on_stashList_customContextMenuRequested(self, pos):
         """
         Private slot to show the context menu of the stash list.
-        
+
         @param pos position of the mouse pointer (QPoint)
         """
         enable = len(self.stashList.selectedItems()) == 1
@@ -395,16 +406,16 @@
         self.__branchAct.setEnabled(enable)
         self.__dropAct.setEnabled(enable)
         self.__clearAct.setEnabled(self.stashList.topLevelItemCount() > 0)
-        
+
         self.__contextMenu.popup(self.mapToGlobal(pos))
-    
+
     @pyqtSlot()
     def on_refreshButton_clicked(self):
         """
         Private slot to refresh the list of shelves.
         """
         self.start(self.__projectDir)
-    
+
     @pyqtSlot()
     def on_sendButton_clicked(self):
         """
@@ -412,7 +423,7 @@
         """
         inputTxt = self.input.text()
         inputTxt += os.linesep
-        
+
         if self.passwordCheckBox.isChecked():
             self.errors.insertPlainText(os.linesep)
             self.errors.ensureCursorVisible()
@@ -420,12 +431,12 @@
             self.errors.insertPlainText(inputTxt)
             self.errors.ensureCursorVisible()
         self.errorGroup.show()
-        
+
         self.__process.write(strToQByteArray(inputTxt))
-        
+
         self.passwordCheckBox.setChecked(False)
         self.input.clear()
-    
+
     @pyqtSlot()
     def on_input_returnPressed(self):
         """
@@ -433,23 +444,23 @@
         """
         self.intercept = True
         self.on_sendButton_clicked()
-    
+
     @pyqtSlot(bool)
     def on_passwordCheckBox_toggled(self, checked):
         """
         Private slot to handle the password checkbox toggled.
-        
+
         @param checked flag indicating the status of the check box (boolean)
         """
         if checked:
             self.input.setEchoMode(QLineEdit.EchoMode.Password)
         else:
             self.input.setEchoMode(QLineEdit.EchoMode.Normal)
-    
+
     def keyPressEvent(self, evt):
         """
         Protected slot to handle a key press event.
-        
+
         @param evt the key press event (QKeyEvent)
         """
         if self.intercept:
@@ -457,21 +468,21 @@
             evt.accept()
             return
         super().keyPressEvent(evt)
-    
+
     def __showPatch(self):
         """
         Private slot to show the contents of the selected stash.
         """
         stashName = self.stashList.selectedItems()[0].text(self.NameColumn)
         self.vcs.gitStashShowPatch(self.__projectDir, stashName)
-    
+
     def __apply(self):
         """
         Private slot to apply the selected stash but keep it.
         """
         stashName = self.stashList.selectedItems()[0].text(self.NameColumn)
         self.vcs.gitStashApply(self.__projectDir, stashName)
-    
+
     def __pop(self):
         """
         Private slot to apply the selected stash and delete it.
@@ -479,7 +490,7 @@
         stashName = self.stashList.selectedItems()[0].text(self.NameColumn)
         self.vcs.gitStashPop(self.__projectDir, stashName)
         self.on_refreshButton_clicked()
-    
+
     def __branch(self):
         """
         Private slot to create a branch from the selected stash.
@@ -487,7 +498,7 @@
         stashName = self.stashList.selectedItems()[0].text(self.NameColumn)
         self.vcs.gitStashBranch(self.__projectDir, stashName)
         self.on_refreshButton_clicked()
-    
+
     def __drop(self):
         """
         Private slot to delete the selected stash.
@@ -496,7 +507,7 @@
         res = self.vcs.gitStashDrop(self.__projectDir, stashName)
         if res:
             self.on_refreshButton_clicked()
-    
+
     def __clear(self):
         """
         Private slot to delete all stashes.

eric ide

mercurial