Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesDefineGuardsDialog.py

Sun, 22 May 2011 16:21:32 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 22 May 2011 16:21:32 +0200
changeset 1053
c54aa980ea8e
parent 1047
b41a36b201e4
child 1131
7781e396c903
permissions
-rw-r--r--

Added an interface to the Mercurial patch queue management.

# -*- coding: utf-8 -*-

# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to define guards for patches.
"""

import os

from PyQt4.QtCore import pyqtSlot, Qt, QProcess, QTimer
from PyQt4.QtGui import QDialog, QDialogButtonBox, QAbstractButton, QListWidgetItem

from E5Gui import E5MessageBox

from .Ui_HgQueuesDefineGuardsDialog import Ui_HgQueuesDefineGuardsDialog

import Preferences
import UI.PixmapCache


class HgQueuesDefineGuardsDialog(QDialog, Ui_HgQueuesDefineGuardsDialog):
    """
    Class implementing a dialog to define guards for patches.
    """
    def __init__(self, vcs, extension, patchesList, parent=None):
        """
        Constructor
        
        @param vcs reference to the vcs object
        @param extension reference to the extension module (Queues)
        @param patchesList list of patches (list of strings)
        @param parent reference to the parent widget (QWidget)
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        
        self.process = QProcess()
        self.vcs = vcs
        self.extension = extension
        
        self.__patches = patchesList[:]
        self.patchSelector.addItems([""] + self.__patches)
        
        self.plusButton.setIcon(UI.PixmapCache.getIcon("plus.png"))
        self.minusButton.setIcon(UI.PixmapCache.getIcon("minus.png"))
        
        self.__dirtyList = False
        self.__currentPatch = ""
    
    def closeEvent(self, e):
        """
        Private slot implementing a close event handler.
        
        @param e close event (QCloseEvent)
        """
        if self.process is not None and \
           self.process.state() != QProcess.NotRunning:
            self.process.terminate()
            QTimer.singleShot(2000, self.process.kill)
            self.process.waitForFinished(3000)
        
        if self.__dirtyList:
            res = E5MessageBox.question(self,
                self.trUtf8("Unsaved Changes"),
                self.trUtf8("""The guards list has been changed."""
                            """ Shall the changes be applied?"""),
                E5MessageBox.StandardButtons(
                    E5MessageBox.Apply | \
                    E5MessageBox.Discard),
                E5MessageBox.Apply)
            if res == E5MessageBox.Apply:
                self.__applyGuards()
            else:
                self.__dirtyList = False
        
        e.accept()
    
    def start(self, path):
        """
        Public slot to start the list command.
        
        @param path name of directory to be listed (string)
        """
        dname, fname = self.vcs.splitPath(path)
        
        # find the root of the repo
        repodir = dname
        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
            repodir = os.path.dirname(repodir)
            if repodir == os.sep:
                return
        
        self.__repodir = repodir
        self.on_patchSelector_activated("")
    
    @pyqtSlot(str)
    def on_patchSelector_activated(self, patch):
        """
        Private slot to get the list of guards defined for the given patch name.
        
        @param patch selected patch name (empty for current patch)
        """
        if self.__dirtyList:
            res = E5MessageBox.question(self,
                self.trUtf8("Unsaved Changes"),
                self.trUtf8("""The guards list has been changed."""
                            """ Shall the changes be applied?"""),
                E5MessageBox.StandardButtons(
                    E5MessageBox.Apply | \
                    E5MessageBox.Discard),
                E5MessageBox.Apply)
            if res == E5MessageBox.Apply:
                self.__applyGuards()
            else:
                self.__dirtyList = False
        
        self.guardsList.clear()
        self.patchNameLabel.setText("")
        
        self.guardCombo.clear()
        guardsList = self.extension.getGuardsList(self.__repodir)
        self.guardCombo.addItems(guardsList)
        self.guardCombo.setEditText("")
        
        ioEncoding = Preferences.getSystem("IOEncoding")
        process = QProcess()
        args = []
        args.append("qguard")
        if patch:
            args.append(patch)
        
        process.setWorkingDirectory(self.__repodir)
        process.start('hg', args)
        procStarted = process.waitForStarted()
        if procStarted:
            finished = process.waitForFinished(30000)
            if finished and process.exitCode() == 0:
                output = \
                    str(process.readAllStandardOutput(), ioEncoding, 'replace').strip()
                if output:
                    patchName, guards = output.split(":", 1)
                    self.patchNameLabel.setText(patchName)
                    guardsList = guards.strip().split()
                    for guard in guardsList:
                        if guard.startswith("+"):
                            icon = UI.PixmapCache.getIcon("plus.png")
                            guard = guard[1:]
                            sign = "+"
                        elif guard.startswith("-"):
                            icon = UI.PixmapCache.getIcon("minus.png")
                            guard = guard[1:]
                            sign = "-"
                        else:
                            continue
                        itm = QListWidgetItem(icon, guard, self.guardsList)
                        itm.setData(Qt.UserRole, sign)
        
        self.on_guardsList_itemSelectionChanged()
    
    @pyqtSlot()
    def on_guardsList_itemSelectionChanged(self):
        """
        Private slot to handle changes of the selection of guards.
        """
        self.removeButton.setEnabled(
            len(self.guardsList.selectedItems()) > 0)
    
    def __getGuard(self, guard):
        """
        Private method to get a reference to a named guard.
        
        @param guard name of the guard (string)
        @return reference to the guard item (QListWidgetItem)
        """
        items = self.guardsList.findItems(guard, Qt.MatchCaseSensitive)
        if items:
            return items[0]
        else:
            return None
    
    @pyqtSlot(str)
    def on_guardCombo_editTextChanged(self, txt):
        """
        Private slot to handle changes of the text of the guard combo.
        
        @param txt contents of the guard combo line edit (string)
        """
        self.addButton.setEnabled(txt != "")
    
    @pyqtSlot()
    def on_addButton_clicked(self):
        """
        Private slot to add a guard definition to the list or change it.
        """
        guard = self.guardCombo.currentText()
        if self.plusButton.isChecked():
            sign = "+"
            icon = UI.PixmapCache.getIcon("plus.png")
        else:
            sign = "-"
            icon = UI.PixmapCache.getIcon("minus.png")
        
        guardItem = self.__getGuard(guard)
        if guardItem:
            # guard already exists, remove it first
            row = self.guardsList.row(guardItem)
            itm = self.guardsList.takeItem(row)
            del itm
        
        itm = QListWidgetItem(icon, guard, self.guardsList)
        itm.setData(Qt.UserRole, sign)
        self.guardsList.sortItems()
        
        self.__dirtyList = True
    
    @pyqtSlot()
    def on_removeButton_clicked(self):
        """
        Private slot to remove guard definitions from the list.
        """
        res = E5MessageBox.yesNo(self,
            self.trUtf8("Remove Guards"),
            self.trUtf8("""Do you really want to remove the selected guards?"""))
        if res:
            for guardItem in self.guardsList.selectedItems():
                row = self.guardsList.row(guardItem)
                itm = self.guardsList.takeItem(row)
                del itm
        
        self.__dirtyList = True
    
    @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.Apply):
            self.__applyGuards()
        elif button == self.buttonBox.button(QDialogButtonBox.Close):
            self.close()
    
    @pyqtSlot()
    def __applyGuards(self):
        """
        Private slot to apply the defined guards to the current patch.
        """
        if self.__dirtyList:
            guardsList = []
            for row in range(self.guardsList.count()):
                itm = self.guardsList.item(row)
                guard = itm.data(Qt.UserRole) + itm.text()
                guardsList.append(guard)
            
            ioEncoding = Preferences.getSystem("IOEncoding")
            process = QProcess()
            args = []
            args.append("qguard")
            args.append(self.patchNameLabel.text())
            if guardsList:
                args.append("--")
                args.extend(guardsList)
            else:
                args.append("--none")
            
            process.setWorkingDirectory(self.__repodir)
            process.start('hg', args)
            procStarted = process.waitForStarted()
            if procStarted:
                finished = process.waitForFinished(30000)
                if finished:
                    if process.exitCode() == 0:
                        self.__dirtyList = False
                        self.on_patchSelector_activated(self.patchNameLabel.text())
                    else:
                        error = \
                            str(process.readAllStandardError(), ioEncoding, 'replace')
                        E5MessageBox.warning(self,
                            self.trUtf8("Apply Guard Definitions"),
                            self.trUtf8("""<p>The defined guards could not be"""
                                        """ applied.</p><p>Reason: {0}</p>""")\
                                .format(error))
                else:
                    E5MessageBox.warning(self,
                        self.trUtf8("Apply Guard Definitions"),
                        self.trUtf8("""The Mercurial process did not finish in time."""))

eric ide

mercurial