eric7/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py

branch
eric7
changeset 8312
800c432b34c8
parent 8218
7c09585bd960
child 8318
962bce857696
diff -r 4e8b98454baa -r 800c432b34c8 eric7/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric7/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py	Sat May 15 18:45:04 2021 +0200
@@ -0,0 +1,270 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show a list of applied and unapplied patches.
+"""
+
+from PyQt5.QtCore import Qt, QCoreApplication
+from PyQt5.QtWidgets import (
+    QDialog, QDialogButtonBox, QHeaderView, QTreeWidgetItem
+)
+
+from .Ui_HgQueuesListDialog import Ui_HgQueuesListDialog
+
+
+class HgQueuesListDialog(QDialog, Ui_HgQueuesListDialog):
+    """
+    Class implementing a dialog to show a list of applied and unapplied
+    patches.
+    """
+    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)
+        self.setWindowFlags(Qt.WindowType.Window)
+        
+        self.buttonBox.button(
+            QDialogButtonBox.StandardButton.Close).setEnabled(False)
+        self.buttonBox.button(
+            QDialogButtonBox.StandardButton.Cancel).setDefault(True)
+        
+        self.vcs = vcs
+        self.__hgClient = vcs.getClient()
+        
+        self.patchesList.header().setSortIndicator(
+            0, Qt.SortOrder.AscendingOrder)
+        
+        self.__statusDict = {
+            "A": self.tr("applied"),
+            "U": self.tr("not applied"),
+            "G": self.tr("guarded"),
+            "D": self.tr("missing"),
+        }
+        
+        self.show()
+        QCoreApplication.processEvents()
+    
+    def closeEvent(self, e):
+        """
+        Protected slot implementing a close event handler.
+        
+        @param e close event (QCloseEvent)
+        """
+        if self.__hgClient.isExecuting():
+            self.__hgClient.cancel()
+        
+        e.accept()
+    
+    def start(self):
+        """
+        Public slot to start the list command.
+        """
+        self.errorGroup.hide()
+        self.activateWindow()
+        
+        self.__getSeries()
+    
+    def __getSeries(self, missing=False):
+        """
+        Private slot to get the list of applied, unapplied and guarded patches
+        and patches missing in the series file.
+        
+        @param missing flag indicating to get the patches missing in the
+            series file (boolean)
+        """
+        if missing:
+            self.__mode = "missing"
+        else:
+            self.__mode = "qseries"
+        
+        args = self.vcs.initCommand("qseries")
+        args.append('--summary')
+        args.append('--verbose')
+        if missing:
+            args.append('--missing')
+        
+        out, err = self.__hgClient.runcommand(args)
+        if err:
+            self.__showError(err)
+        if out:
+            for line in out.splitlines():
+                self.__processOutputLine(line)
+                if self.__hgClient.wasCanceled():
+                    self.__mode = ""
+                    break
+        if self.__mode == "qseries":
+            self.__getSeries(True)
+        elif self.__mode == "missing":
+            self.__getTop()
+        else:
+            self.__finish()
+    
+    def __getTop(self):
+        """
+        Private slot to get patch at the top of the stack.
+        """
+        self.__mode = "qtop"
+        
+        args = self.vcs.initCommand("qtop")
+        
+        out, err = self.__hgClient.runcommand(args)
+        if err:
+            self.__showError(err)
+        if out:
+            for line in out.splitlines():
+                self.__processOutputLine(line)
+                if self.__hgClient.wasCanceled():
+                    break
+        self.__finish()
+    
+    def __finish(self):
+        """
+        Private slot called when the process finished or the user pressed
+        the button.
+        """
+        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).setFocus(
+                Qt.FocusReason.OtherFocusReason)
+        
+        if self.patchesList.topLevelItemCount() == 0:
+            # no patches present
+            self.__generateItem(
+                0, "", self.tr("no patches found"), "", True)
+        self.__resizeColumns()
+        self.__resort()
+    
+    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
+        ):
+            self.close()
+        elif button == self.buttonBox.button(
+            QDialogButtonBox.StandardButton.Cancel
+        ):
+            self.__mode = ""
+            self.__hgClient.cancel()
+    
+    def __resort(self):
+        """
+        Private method to resort the tree.
+        """
+        self.patchesList.sortItems(
+            self.patchesList.sortColumn(),
+            self.patchesList.header().sortIndicatorOrder())
+    
+    def __resizeColumns(self):
+        """
+        Private method to resize the list columns.
+        """
+        self.patchesList.header().resizeSections(
+            QHeaderView.ResizeMode.ResizeToContents)
+        self.patchesList.header().setStretchLastSection(True)
+    
+    def __generateItem(self, index, status, name, summary, error=False):
+        """
+        Private method to generate a patch item in the list of patches.
+        
+        @param index index of the patch (integer, -1 for missing)
+        @param status status of the patch (string)
+        @param name name of the patch (string)
+        @param summary first line of the patch header (string)
+        @param error flag indicating an error entry (boolean)
+        """
+        if error:
+            itm = QTreeWidgetItem(self.patchesList, [
+                "",
+                name,
+                "",
+                summary
+            ])
+        else:
+            if index == -1:
+                index = ""
+            try:
+                statusStr = self.__statusDict[status]
+            except KeyError:
+                statusStr = self.tr("unknown")
+            itm = QTreeWidgetItem(self.patchesList)
+            itm.setData(0, Qt.ItemDataRole.DisplayRole, index)
+            itm.setData(1, Qt.ItemDataRole.DisplayRole, name)
+            itm.setData(2, Qt.ItemDataRole.DisplayRole, statusStr)
+            itm.setData(3, Qt.ItemDataRole.DisplayRole, summary)
+            if status == "A":
+                # applied
+                for column in range(itm.columnCount()):
+                    itm.setForeground(column, Qt.GlobalColor.blue)
+            elif status == "D":
+                # missing
+                for column in range(itm.columnCount()):
+                    itm.setForeground(column, Qt.GlobalColor.red)
+        
+        itm.setTextAlignment(0, Qt.AlignmentFlag.AlignRight)
+        itm.setTextAlignment(2, Qt.AlignmentFlag.AlignHCenter)
+    
+    def __markTopItem(self, name):
+        """
+        Private slot to mark the top patch entry.
+        
+        @param name name of the patch (string)
+        """
+        items = self.patchesList.findItems(
+            name, Qt.MatchFlag.MatchCaseSensitive, 1)
+        if items:
+            itm = items[0]
+            for column in range(itm.columnCount()):
+                font = itm.font(column)
+                font.setBold(True)
+                itm.setFont(column, font)
+    
+    def __processOutputLine(self, line):
+        """
+        Private method to process the lines of output.
+        
+        @param line output line to be processed (string)
+        """
+        if self.__mode == "qtop":
+            self.__markTopItem(line)
+        else:
+            li = line.split(": ", 1)
+            if len(li) == 1:
+                data, summary = li[0][:-1], ""
+            else:
+                data, summary = li[0], li[1]
+            li = data.split(None, 2)
+            if len(li) == 2:
+                # missing entry
+                index, status, name = -1, li[0], li[1]
+            elif len(li) == 3:
+                index, status, name = li[:3]
+            else:
+                return
+            self.__generateItem(index, status, name, summary)
+    
+    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()

eric ide

mercurial