Started with support for Mercurial queues extension.

Sat, 14 May 2011 20:00:13 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 14 May 2011 20:00:13 +0200
changeset 1034
8a7fa049e9d3
parent 1033
bfc17ed5ab1a
child 1035
2cd7817ac659

Started with support for Mercurial queues extension.

Dictionaries/words.dic file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.ui file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesNewPatchDialog.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesNewPatchDialog.ui file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/QueuesExtension/ProjectHelper.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/QueuesExtension/__init__.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/QueuesExtension/queues.py file | annotate | diff | comparison | revisions
Plugins/VcsPlugins/vcsMercurial/hg.py file | annotate | diff | comparison | revisions
eric5.e4p file | annotate | diff | comparison | revisions
--- a/Dictionaries/words.dic	Fri May 13 20:23:42 2011 +0200
+++ b/Dictionaries/words.dic	Sat May 14 20:00:13 2011 +0200
@@ -2,4 +2,5 @@
 detlev
 offenbachs
 Eric5
-IDE
\ No newline at end of file
+IDE
+unapplied
\ No newline at end of file
--- a/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py	Fri May 13 20:23:42 2011 +0200
+++ b/Plugins/VcsPlugins/vcsMercurial/HgDiffDialog.py	Sat May 14 20:00:13 2011 +0200
@@ -84,13 +84,14 @@
         else:
             return str(version)
     
-    def start(self, fn, versions=None, bundle=None):
+    def start(self, fn, versions=None, bundle=None, qdiff=False):
         """
         Public slot to start the hg diff command.
         
         @param fn filename to be diffed (string)
         @param versions list of versions to be diffed (list of up to 2 strings or None)
         @param bundle name of a bundle file (string)
+        @param qdiff flag indicating qdiff command shall be used (boolean)
         """
         self.errorGroup.hide()
         self.inputGroup.show()
@@ -103,34 +104,38 @@
         self.paras = 0
         
         args = []
-        args.append('diff')
-        self.vcs.addArguments(args, self.vcs.options['global'])
-        self.vcs.addArguments(args, self.vcs.options['diff'])
-        
-        if bundle:
-            args.append('--repository')
-            args.append(bundle)
-        elif self.vcs.bundleFile and os.path.exists(self.vcs.bundleFile):
-            args.append('--repository')
-            args.append(self.vcs.bundleFile)
-        
-        if versions is not None:
-            self.raise_()
-            self.activateWindow()
+        if qdiff:
+            args.append('qdiff')
+            self.setWindowTitle(self.trUtf8("Patch Contents"))
+        else:
+            args.append('diff')
+            self.vcs.addArguments(args, self.vcs.options['global'])
+            self.vcs.addArguments(args, self.vcs.options['diff'])
+            
+            if bundle:
+                args.append('--repository')
+                args.append(bundle)
+            elif self.vcs.bundleFile and os.path.exists(self.vcs.bundleFile):
+                args.append('--repository')
+                args.append(self.vcs.bundleFile)
             
-            rev1 = self.__getVersionArg(versions[0])
-            rev2 = None
-            if len(versions) == 2:
-                rev2 = self.__getVersionArg(versions[1])
-            
-            if rev1 is not None or rev2 is not None:
-                args.append('-r')
-                if rev1 is not None and rev2 is not None:
-                    args.append('{0}:{1}'.format(rev1, rev2))
-                elif rev2 is None:
-                    args.append(rev1)
-                elif rev1 is None:
-                    args.append(':{0}'.format(rev2))
+            if versions is not None:
+                self.raise_()
+                self.activateWindow()
+                
+                rev1 = self.__getVersionArg(versions[0])
+                rev2 = None
+                if len(versions) == 2:
+                    rev2 = self.__getVersionArg(versions[1])
+                
+                if rev1 is not None or rev2 is not None:
+                    args.append('-r')
+                    if rev1 is not None and rev2 is not None:
+                        args.append('{0}:{1}'.format(rev1, rev2))
+                    elif rev2 is None:
+                        args.append(rev1)
+                    elif rev1 is None:
+                        args.append(':{0}'.format(rev2))
         
         if isinstance(fn, list):
             dname, fnames = self.vcs.splitPathList(fn)
--- a/Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py	Fri May 13 20:23:42 2011 +0200
+++ b/Plugins/VcsPlugins/vcsMercurial/ProjectHelper.py	Sat May 14 20:00:13 2011 +0200
@@ -17,6 +17,7 @@
 from VCS.ProjectHelper import VcsProjectHelper
 
 from .BookmarksExtension.ProjectHelper import BookmarksProjectHelper
+from .QueuesExtension.ProjectHelper import QueuesProjectHelper
 
 from E5Gui.E5Action import E5Action
 
@@ -42,6 +43,7 @@
         # instantiate the extensions
         self.__extensions = {
             "bookmarks" : BookmarksProjectHelper(),
+            "mq" : QueuesProjectHelper(),
         }
     
     def setObjects(self, vcsObject, projectObject):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py	Sat May 14 20:00:13 2011 +0200
@@ -0,0 +1,355 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show a list of applied and unapplied patches.
+"""
+
+import os
+
+from PyQt4.QtCore import pyqtSlot, QProcess, Qt, QTimer
+from PyQt4.QtGui import QDialog, QDialogButtonBox, QHeaderView, QTreeWidgetItem, \
+    QLineEdit
+
+from E5Gui import E5MessageBox
+
+from .Ui_HgQueuesListDialog import Ui_HgQueuesListDialog
+
+import Preferences
+
+
+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)
+        """
+        QDialog.__init__(self, parent)
+        self.setupUi(self)
+        
+        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
+        
+        self.process = QProcess()
+        self.vcs = vcs
+        
+        self.patchesList.header().setSortIndicator(0, Qt.AscendingOrder)
+        
+        self.process.finished.connect(self.__procFinished)
+        self.process.readyReadStandardOutput.connect(self.__readStdout)
+        self.process.readyReadStandardError.connect(self.__readStderr)
+    
+    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)
+        
+        e.accept()
+    
+    def start(self, path):
+        """
+        Public slot to start the list command.
+        
+        @param path name of directory to be listed (string)
+        """
+        self.errorGroup.hide()
+        
+        self.intercept = False
+        self.activateWindow()
+        
+        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.__patchesCount = 0
+        self.__getApplied()
+    
+    def __getApplied(self):
+        """
+        Private slot to get the list of applied patches.
+        """
+        self.__mode = "qapplied"
+        
+        args = []
+        args.append('qapplied')
+        args.append('--summary')
+        
+        self.process.kill()
+        self.process.setWorkingDirectory(self.__repodir)
+        
+        self.process.start('hg', args)
+        procStarted = self.process.waitForStarted()
+        if not procStarted:
+            self.inputGroup.setEnabled(False)
+            self.inputGroup.hide()
+            E5MessageBox.critical(self,
+                self.trUtf8('Process Generation Error'),
+                self.trUtf8(
+                    'The process {0} could not be started. '
+                    'Ensure, that it is in the search path.'
+                ).format('hg'))
+        else:
+            self.inputGroup.setEnabled(True)
+            self.inputGroup.show()
+    
+    def __getUnapplied(self):
+        """
+        Private slot to get the list of unapplied patches.
+        """
+        self.__mode = "qunapplied"
+        
+        args = []
+        args.append('qunapplied')
+        args.append('--summary')
+        
+        self.process.kill()
+        self.process.setWorkingDirectory(self.__repodir)
+        
+        self.process.start('hg', args)
+        procStarted = self.process.waitForStarted()
+        if not procStarted:
+            self.inputGroup.setEnabled(False)
+            self.inputGroup.hide()
+            E5MessageBox.critical(self,
+                self.trUtf8('Process Generation Error'),
+                self.trUtf8(
+                    'The process {0} could not be started. '
+                    'Ensure, that it is in the search path.'
+                ).format('hg'))
+        else:
+            self.inputGroup.setEnabled(True)
+            self.inputGroup.show()
+    
+    def __getTop(self):
+        """
+        Private slot to get patch at the top of the stack.
+        """
+        self.__mode = "qtop"
+        
+        args = []
+        args.append('qtop')
+        
+        self.process.kill()
+        self.process.setWorkingDirectory(self.__repodir)
+        
+        self.process.start('hg', args)
+        procStarted = self.process.waitForStarted()
+        if not procStarted:
+            self.inputGroup.setEnabled(False)
+            self.inputGroup.hide()
+            E5MessageBox.critical(self,
+                self.trUtf8('Process Generation Error'),
+                self.trUtf8(
+                    'The process {0} could not be started. '
+                    'Ensure, that it is in the search path.'
+                ).format('hg'))
+        else:
+            self.inputGroup.setEnabled(True)
+            self.inputGroup.show()
+    
+    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.NotRunning:
+            self.process.terminate()
+            QTimer.singleShot(2000, self.process.kill)
+            self.process.waitForFinished(3000)
+        
+        self.inputGroup.setEnabled(False)
+        self.inputGroup.hide()
+        
+        self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
+        self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
+        self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
+        self.buttonBox.button(QDialogButtonBox.Close).setFocus(Qt.OtherFocusReason)
+        
+        self.process = None
+        
+        if self.patchesList.topLevelItemCount() == 0:
+            # no bookmarks defined
+            self.__generateItem(self.trUtf8("no patches found"), "")
+        self.patchesList.doItemsLayout()
+        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.Close):
+            self.close()
+        elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
+            self.__finish()
+    
+    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)
+        """
+        if self.__mode == "qapplied":
+            self.__getUnapplied()
+        elif self.__mode == "qunapplied":
+            self.__getTop()
+        else:
+            self.__finish()
+    
+    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.ResizeToContents)
+        self.patchesList.header().setStretchLastSection(True)
+    
+    def __generateItem(self, name, summary):
+        """
+        Private method to generate a patch item in the list of patches.
+        
+        @param name name of the patch (string)
+        @param summary first line of the patch header (string) 
+        """
+        self.__patchesCount += 1
+        itm = QTreeWidgetItem(self.patchesList, [
+            "{0:>7}".format(self.__patchesCount),
+            name,
+            self.__mode == "qapplied" and \
+                self.trUtf8("applied") or \
+                self.trUtf8("not applied"),
+            summary
+        ])
+        itm.setTextAlignment(0, Qt.AlignRight)
+        itm.setTextAlignment(2, Qt.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.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 __readStdout(self):
+        """
+        Private slot to handle the readyReadStdout signal.
+        
+        It reads the output of the process, formats it and inserts it into
+        the contents pane.
+        """
+        self.process.setReadChannel(QProcess.StandardOutput)
+        
+        while self.process.canReadLine():
+            s = str(self.process.readLine(),
+                    Preferences.getSystem("IOEncoding"),
+                    'replace').strip()
+            if self.__mode == "qtop":
+                self.__markTopItem(s)
+            else:
+                l = s.split(": ", 1)
+                if len(l) == 1:
+                    name, summary = l[0][:-1], ""
+                else:
+                    name, summary = l[0], l[1]
+                self.__generateItem(name, summary)
+    
+    def __readStderr(self):
+        """
+        Private slot to handle the readyReadStderr signal.
+        
+        It reads the error output of the process and inserts it into the
+        error pane.
+        """
+        if self.process is not None:
+            self.errorGroup.show()
+            s = str(self.process.readAllStandardError(),
+                    Preferences.getSystem("IOEncoding"),
+                    'replace')
+            self.errors.insertPlainText(s)
+            self.errors.ensureCursorVisible()
+    
+    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.Password)
+        else:
+            self.input.setEchoMode(QLineEdit.Normal)
+    
+    @pyqtSlot()
+    def on_sendButton_clicked(self):
+        """
+        Private slot to send the input to the subversion process.
+        """
+        input = self.input.text()
+        input += os.linesep
+        
+        if self.passwordCheckBox.isChecked():
+            self.errors.insertPlainText(os.linesep)
+            self.errors.ensureCursorVisible()
+        else:
+            self.errors.insertPlainText(input)
+            self.errors.ensureCursorVisible()
+        
+        self.process.write(input)
+        
+        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:
+            self.intercept = False
+            evt.accept()
+            return
+        QDialog.keyPressEvent(self, evt)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.ui	Sat May 14 20:00:13 2011 +0200
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HgQueuesListDialog</class>
+ <widget class="QDialog" name="HgQueuesListDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>634</width>
+    <height>494</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>List of Patches</string>
+  </property>
+  <property name="whatsThis">
+   <string>&lt;b&gt;List of Patches&lt;/b&gt;
+&lt;p&gt;This dialog shows a list of applied and unapplied patches.&lt;/p&gt;</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout">
+   <item>
+    <widget class="QTreeWidget" name="patchesList">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>2</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="whatsThis">
+      <string>&lt;b&gt;Patches List&lt;/b&gt;
+&lt;p&gt;This shows a list of applied and unapplied patches.&lt;/p&gt;</string>
+     </property>
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="itemsExpandable">
+      <bool>false</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string notr="true">#</string>
+      </property>
+      <property name="toolTip">
+       <string/>
+      </property>
+      <property name="textAlignment">
+       <set>AlignLeft|AlignVCenter</set>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Name</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Status</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Summary</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="errorGroup">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>1</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Errors</string>
+     </property>
+     <layout class="QVBoxLayout">
+      <item>
+       <widget class="QTextEdit" name="errors">
+        <property name="focusPolicy">
+         <enum>Qt::NoFocus</enum>
+        </property>
+        <property name="readOnly">
+         <bool>true</bool>
+        </property>
+        <property name="acceptRichText">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="inputGroup">
+     <property name="title">
+      <string>Input</string>
+     </property>
+     <layout class="QGridLayout">
+      <item row="1" column="1">
+       <spacer>
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Expanding</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>327</width>
+          <height>29</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="1" column="2">
+       <widget class="QPushButton" name="sendButton">
+        <property name="toolTip">
+         <string>Press to send the input to the hg process</string>
+        </property>
+        <property name="text">
+         <string>&amp;Send</string>
+        </property>
+        <property name="shortcut">
+         <string>Alt+S</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0" colspan="3">
+       <widget class="QLineEdit" name="input">
+        <property name="toolTip">
+         <string>Enter data to be sent to the hg process</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QCheckBox" name="passwordCheckBox">
+        <property name="toolTip">
+         <string>Select to switch the input field to password mode</string>
+        </property>
+        <property name="text">
+         <string>&amp;Password Mode</string>
+        </property>
+        <property name="shortcut">
+         <string>Alt+P</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+ <tabstops>
+  <tabstop>input</tabstop>
+  <tabstop>passwordCheckBox</tabstop>
+  <tabstop>sendButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesNewPatchDialog.py	Sat May 14 20:00:13 2011 +0200
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to get the data for a new patch.
+"""
+
+from PyQt4.QtCore import pyqtSlot, QDate
+from PyQt4.QtGui import QDialog, QDialogButtonBox
+
+from .Ui_HgQueuesNewPatchDialog import Ui_HgQueuesNewPatchDialog
+
+
+class HgQueuesNewPatchDialog(QDialog, Ui_HgQueuesNewPatchDialog):
+    """
+    Class implementing a dialog to get the data for a new patch.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        QDialog.__init__(self, parent)
+        self.setupUi(self)
+        
+        self.dateEdit.setDate(QDate.currentDate())
+        
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False)
+    
+    def __updateUI(self):
+        """
+        Private slot to update the UI.
+        """
+        enable = self.nameEdit.text() != "" and \
+                 self.messageEdit.toPlainText() != ""
+        if self.userGroup.isChecked():
+            enable = enable and \
+                (self.currentUserCheckBox.isChecked() or \
+                 self.userEdit.text() != "")
+        
+        self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enable)
+    
+    @pyqtSlot(str)
+    def on_nameEdit_textChanged(self, txt):
+        """
+        Private slot to handle changes of the patch name.
+        
+        @param txt text of the edit (string)
+        """
+        self.__updateUI()
+    
+    @pyqtSlot()
+    def on_messageEdit_textChanged(self):
+        """
+        Private slot to handle changes of the patch message.
+        
+        @param txt text of the edit (string)
+        """
+        self.__updateUI()
+    
+    def getData(self):
+        """
+        Public method to retrieve the entered data.
+        
+        @return tuple giving the patch name and message, a tuple giving a
+            flag indicating to set the user, a flag indicating to use the
+            current user and the user name and another tuple giving a flag
+            indicating to set the date, a flag indicating to use the
+            current date and the date (string, string, (boolean, boolean, string),
+            (boolean, boolean, string))
+        """
+        userData = (self.userGroup.isChecked(),
+                    self.currentUserCheckBox.isChecked(), 
+                    self.userEdit.text())
+        dateData = (self.dateGroup.isChecked(), 
+                    self.currentDateCheckBox.isChecked(), 
+                    self.dateEdit.date().toString("yyyy-MM-dd"))
+        return (self.nameEdit.text(), self.messageEdit.toPlainText(), 
+            userData, dateData)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesNewPatchDialog.ui	Sat May 14 20:00:13 2011 +0200
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>HgQueuesNewPatchDialog</class>
+ <widget class="QDialog" name="HgQueuesNewPatchDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>350</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>New Patch</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QGridLayout" name="gridLayout_3">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Name:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLineEdit" name="nameEdit">
+     <property name="toolTip">
+      <string>Enter the patch name</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="label_2">
+     <property name="text">
+      <string>Message:</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1">
+    <widget class="QPlainTextEdit" name="messageEdit">
+     <property name="toolTip">
+      <string>Enter the commit message for the patch</string>
+     </property>
+     <property name="tabChangesFocus">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2">
+    <widget class="QGroupBox" name="userGroup">
+     <property name="toolTip">
+      <string>Select to give user information</string>
+     </property>
+     <property name="title">
+      <string>User</string>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+     <property name="checked">
+      <bool>false</bool>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="0" column="0" colspan="2">
+       <widget class="QCheckBox" name="currentUserCheckBox">
+        <property name="toolTip">
+         <string>Select to use the name of the current user</string>
+        </property>
+        <property name="text">
+         <string>Use current user</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_3">
+        <property name="text">
+         <string>Username:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="userEdit">
+        <property name="toolTip">
+         <string>Enter the user name to be used for the patch</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="3" column="0" colspan="2">
+    <widget class="QGroupBox" name="dateGroup">
+     <property name="toolTip">
+      <string>Select to give date information</string>
+     </property>
+     <property name="title">
+      <string>Date</string>
+     </property>
+     <property name="checkable">
+      <bool>true</bool>
+     </property>
+     <property name="checked">
+      <bool>false</bool>
+     </property>
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0" colspan="3">
+       <widget class="QCheckBox" name="currentDateCheckBox">
+        <property name="toolTip">
+         <string>Select to use the current date</string>
+        </property>
+        <property name="text">
+         <string>Use current date</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QLabel" name="label_4">
+        <property name="text">
+         <string>Date:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QDateEdit" name="dateEdit">
+        <property name="toolTip">
+         <string>Enter the date to be used for the patch</string>
+        </property>
+        <property name="displayFormat">
+         <string notr="true">yyyy-MM-dd</string>
+        </property>
+        <property name="calendarPopup">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>241</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item row="4" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>nameEdit</tabstop>
+  <tabstop>messageEdit</tabstop>
+  <tabstop>userGroup</tabstop>
+  <tabstop>currentUserCheckBox</tabstop>
+  <tabstop>userEdit</tabstop>
+  <tabstop>dateGroup</tabstop>
+  <tabstop>currentDateCheckBox</tabstop>
+  <tabstop>dateEdit</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>HgQueuesNewPatchDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>119</x>
+     <y>333</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>14</x>
+     <y>333</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>HgQueuesNewPatchDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>157</x>
+     <y>326</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>45</x>
+     <y>326</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>currentUserCheckBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>userEdit</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>50</x>
+     <y>184</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>98</x>
+     <y>208</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>currentUserCheckBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>label_3</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>22</x>
+     <y>182</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>23</x>
+     <y>204</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>currentDateCheckBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>dateEdit</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>55</x>
+     <y>269</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>82</x>
+     <y>294</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>currentDateCheckBox</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>label_4</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>36</x>
+     <y>271</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>297</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/ProjectHelper.py	Sat May 14 20:00:13 2011 +0200
@@ -0,0 +1,473 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the queues extension project helper.
+"""
+
+from PyQt4.QtCore import QObject
+from PyQt4.QtGui import QMenu
+
+from E5Gui.E5Action import E5Action
+
+
+class QueuesProjectHelper(QObject):
+    """
+    Class implementing the queues extension project helper.
+    """
+    def __init__(self):
+        """
+        Constructor
+        """
+        QObject.__init__(self)
+        
+        self.actions = []
+        
+        self.initActions()
+    
+    def setObjects(self, vcsObject, projectObject):
+        """
+        Public method to set references to the vcs and project objects.
+        
+        @param vcsObject reference to the vcs object
+        @param projectObject reference to the project object
+        """
+        self.vcs = vcsObject
+        self.project = projectObject
+    
+    def getActions(self):
+        """
+        Public method to get a list of all actions.
+        
+        @return list of all actions (list of E5Action)
+        """
+        return self.actions[:]
+    
+    def initActions(self):
+        """
+        Public method to generate the action objects.
+        """
+        self.hgQueueNewAct = E5Action(self.trUtf8('New Patch'),
+                self.trUtf8('New Patch...'),
+                0, 0, self, 'mercurial_queues_new')
+        self.hgQueueNewAct.setStatusTip(self.trUtf8(
+            'Create a new patch'
+        ))
+        self.hgQueueNewAct.setWhatsThis(self.trUtf8(
+            """<b>New Patch</b>"""
+            """<p>This creates a new named patch.</p>"""
+        ))
+        self.hgQueueNewAct.triggered[()].connect(self.__hgQueueNewPatch)
+        self.actions.append(self.hgQueueNewAct)
+        
+        self.hgQueueRefreshAct = E5Action(self.trUtf8('Update Current Patch'),
+                self.trUtf8('Update Current Patch'),
+                0, 0, self, 'mercurial_queues_refresh')
+        self.hgQueueRefreshAct.setStatusTip(self.trUtf8(
+            'Update the current patch'
+        ))
+        self.hgQueueRefreshAct.setWhatsThis(self.trUtf8(
+            """<b>Update Current Patch</b>"""
+            """<p>This updates the current patch.</p>"""
+        ))
+        self.hgQueueRefreshAct.triggered[()].connect(self.__hgQueueRefreshPatch)
+        self.actions.append(self.hgQueueRefreshAct)
+        
+        self.hgQueueDiffAct = E5Action(self.trUtf8('Show Current Patch'),
+                self.trUtf8('Show Current Patch...'),
+                0, 0, self, 'mercurial_queues_show')
+        self.hgQueueDiffAct.setStatusTip(self.trUtf8(
+            'Show the contents the current patch'
+        ))
+        self.hgQueueDiffAct.setWhatsThis(self.trUtf8(
+            """<b>Show Current Patch</b>"""
+            """<p>This shows the contents of the current patch including"""
+            """ any changes which have been made in the working directory"""
+            """ since the last refresh.</p>"""
+        ))
+        self.hgQueueDiffAct.triggered[()].connect(self.__hgQueueShowPatch)
+        self.actions.append(self.hgQueueDiffAct)
+        
+        self.hgQueueListAct = E5Action(self.trUtf8('List Patches'),
+                self.trUtf8('List Patches...'),
+                0, 0, self, 'mercurial_queues_list')
+        self.hgQueueListAct.setStatusTip(self.trUtf8(
+            'List applied and unapplied patches'
+        ))
+        self.hgQueueListAct.setWhatsThis(self.trUtf8(
+            """<b>List Patches</b>"""
+            """<p>This list all applied and unapplied patches.</p>"""
+        ))
+        self.hgQueueListAct.triggered[()].connect(self.__hgQueueListPatches)
+        self.actions.append(self.hgQueueListAct)
+        
+        self.hgQueueFinishAct = E5Action(self.trUtf8('Finish Applied Patches'),
+                self.trUtf8('Finish Applied Patches'),
+                0, 0, self, 'mercurial_queues_finish_applied')
+        self.hgQueueFinishAct.setStatusTip(self.trUtf8(
+            'Finish applied patches'
+        ))
+        self.hgQueueFinishAct.setWhatsThis(self.trUtf8(
+            """<b>Finish Applied Patches</b>"""
+            """<p>This finishes the applied patches) by moving them out of"""
+            """ mq control into regular repository history.</p>"""
+        ))
+        self.hgQueueFinishAct.triggered[()].connect(self.__hgQueueFinishAppliedPatches)
+        self.actions.append(self.hgQueueFinishAct)
+        
+        self.__initPushPopActions()
+        self.__initPushPopForceActions()
+    
+    def __initPushPopActions(self):
+        """
+        Public method to generate the push and pop action objects.
+        """
+        self.hgQueuePushAct = E5Action(self.trUtf8('Push Next Patch'),
+                self.trUtf8('Push Next Patch'),
+                0, 0, self, 'mercurial_queues_push_next')
+        self.hgQueuePushAct.setStatusTip(self.trUtf8(
+            'Push the next patch onto the stack'
+        ))
+        self.hgQueuePushAct.setWhatsThis(self.trUtf8(
+            """<b>Push Next Patch</b>"""
+            """<p>This pushes the next patch onto the stack of applied patches.</p>"""
+        ))
+        self.hgQueuePushAct.triggered[()].connect(self.__hgQueuePushPatch)
+        self.actions.append(self.hgQueuePushAct)
+        
+        self.hgQueuePushAllAct = E5Action(self.trUtf8('Push All Patches'),
+                self.trUtf8('Push All Patches'),
+                0, 0, self, 'mercurial_queues_push_all')
+        self.hgQueuePushAllAct.setStatusTip(self.trUtf8(
+            'Push all patches onto the stack'
+        ))
+        self.hgQueuePushAllAct.setWhatsThis(self.trUtf8(
+            """<b>Push All Patches</b>"""
+            """<p>This pushes all patches onto the stack of applied patches.</p>"""
+        ))
+        self.hgQueuePushAllAct.triggered[()].connect(self.__hgQueuePushAllPatches)
+        self.actions.append(self.hgQueuePushAllAct)
+        
+        self.hgQueuePushUntilAct = E5Action(self.trUtf8('Push Patches'),
+                self.trUtf8('Push Patches'),
+                0, 0, self, 'mercurial_queues_push_until')
+        self.hgQueuePushUntilAct.setStatusTip(self.trUtf8(
+            'Push patches onto the stack'
+        ))
+        self.hgQueuePushUntilAct.setWhatsThis(self.trUtf8(
+            """<b>Push Patches</b>"""
+            """<p>This pushes patches onto the stack  of applied patches until"""
+            """ a named patch is at the top of the stack.</p>"""
+        ))
+        self.hgQueuePushUntilAct.triggered[()].connect(self.__hgQueuePushPatches)
+        self.actions.append(self.hgQueuePushUntilAct)
+        
+        self.hgQueuePopAct = E5Action(self.trUtf8('Pop Current Patch'),
+                self.trUtf8('Pop Current Patch'),
+                0, 0, self, 'mercurial_queues_pop_current')
+        self.hgQueuePopAct.setStatusTip(self.trUtf8(
+            'Pop the current patch off the stack'
+        ))
+        self.hgQueuePopAct.setWhatsThis(self.trUtf8(
+            """<b>Pop Current Patch</b>"""
+            """<p>This pops the current patch off the stack of applied patches.</p>"""
+        ))
+        self.hgQueuePopAct.triggered[()].connect(self.__hgQueuePopPatch)
+        self.actions.append(self.hgQueuePopAct)
+        
+        self.hgQueuePopAllAct = E5Action(self.trUtf8('Pop All Patches'),
+                self.trUtf8('Pop All Patches'),
+                0, 0, self, 'mercurial_queues_pop_all')
+        self.hgQueuePopAllAct.setStatusTip(self.trUtf8(
+            'Pop all patches off the stack'
+        ))
+        self.hgQueuePopAllAct.setWhatsThis(self.trUtf8(
+            """<b>Pop All Patches</b>"""
+            """<p>This pops all patches off the stack of applied patches.</p>"""
+        ))
+        self.hgQueuePopAllAct.triggered[()].connect(self.__hgQueuePopAllPatches)
+        self.actions.append(self.hgQueuePopAllAct)
+        
+        self.hgQueuePopUntilAct = E5Action(self.trUtf8('Pop Patches'),
+                self.trUtf8('Pop Patches'),
+                0, 0, self, 'mercurial_queues_pop_until')
+        self.hgQueuePopUntilAct.setStatusTip(self.trUtf8(
+            'Pop patches off the stack'
+        ))
+        self.hgQueuePopUntilAct.setWhatsThis(self.trUtf8(
+            """<b>Pop Patches</b>"""
+            """<p>This pops patches off the stack of applied patches until a named"""
+            """ patch is at the top of the stack.</p>"""
+        ))
+        self.hgQueuePopUntilAct.triggered[()].connect(self.__hgQueuePopPatches)
+        self.actions.append(self.hgQueuePopUntilAct)
+    
+    def __initPushPopForceActions(self):
+        """
+        Public method to generate the push and pop (force) action objects.
+        """
+        self.hgQueuePushForceAct = E5Action(self.trUtf8('Push Next Patch'),
+                self.trUtf8('Push Next Patch'),
+                0, 0, self, 'mercurial_queues_push_next_force')
+        self.hgQueuePushForceAct.setStatusTip(self.trUtf8(
+            'Push the next patch onto the stack on top of local changes'
+        ))
+        self.hgQueuePushForceAct.setWhatsThis(self.trUtf8(
+            """<b>Push Next Patch</b>"""
+            """<p>This pushes the next patch onto the stack of applied patches"""
+            """ on top of local changes.</p>"""
+        ))
+        self.hgQueuePushForceAct.triggered[()].connect(self.__hgQueuePushPatchForced)
+        self.actions.append(self.hgQueuePushForceAct)
+        
+        self.hgQueuePushAllForceAct = E5Action(self.trUtf8('Push All Patches'),
+                self.trUtf8('Push All Patches'),
+                0, 0, self, 'mercurial_queues_push_all_force')
+        self.hgQueuePushAllForceAct.setStatusTip(self.trUtf8(
+            'Push all patches onto the stack on top of local changes'
+        ))
+        self.hgQueuePushAllForceAct.setWhatsThis(self.trUtf8(
+            """<b>Push All Patches</b>"""
+            """<p>This pushes all patches onto the stack of applied patches"""
+            """ on top of local changes.</p>"""
+        ))
+        self.hgQueuePushAllForceAct.triggered[()].connect(
+            self.__hgQueuePushAllPatchesForced)
+        self.actions.append(self.hgQueuePushAllForceAct)
+        
+        self.hgQueuePushUntilForceAct = E5Action(self.trUtf8('Push Patches'),
+                self.trUtf8('Push Patches'),
+                0, 0, self, 'mercurial_queues_push_until_force')
+        self.hgQueuePushUntilForceAct.setStatusTip(self.trUtf8(
+            'Push patches onto the stack on top of local changes'
+        ))
+        self.hgQueuePushUntilForceAct.setWhatsThis(self.trUtf8(
+            """<b>Push Patches</b>"""
+            """<p>This pushes patches onto the stack  of applied patches until"""
+            """ a named patch is at the top of the stack on top of local changes.</p>"""
+        ))
+        self.hgQueuePushUntilForceAct.triggered[()].connect(
+            self.__hgQueuePushPatchesForced)
+        self.actions.append(self.hgQueuePushUntilForceAct)
+        
+        self.hgQueuePopForceAct = E5Action(self.trUtf8('Pop Current Patch'),
+                self.trUtf8('Pop Current Patch'),
+                0, 0, self, 'mercurial_queues_pop_current_force')
+        self.hgQueuePopForceAct.setStatusTip(self.trUtf8(
+            'Pop the current patch off the stack forgetting local changes'
+        ))
+        self.hgQueuePopForceAct.setWhatsThis(self.trUtf8(
+            """<b>Pop Current Patch</b>"""
+            """<p>This pops the current patch off the stack of applied patches"""
+            """ forgetting local changes.</p>"""
+        ))
+        self.hgQueuePopForceAct.triggered[()].connect(self.__hgQueuePopPatchForced)
+        self.actions.append(self.hgQueuePopForceAct)
+        
+        self.hgQueuePopAllForceAct = E5Action(self.trUtf8('Pop All Patches'),
+                self.trUtf8('Pop All Patches'),
+                0, 0, self, 'mercurial_queues_pop_all_force')
+        self.hgQueuePopAllForceAct.setStatusTip(self.trUtf8(
+            'Pop all patches off the stack forgetting local changes'
+        ))
+        self.hgQueuePopAllForceAct.setWhatsThis(self.trUtf8(
+            """<b>Pop All Patches</b>"""
+            """<p>This pops all patches off the stack of applied patches"""
+            """  forgetting local changes.</p>"""
+        ))
+        self.hgQueuePopAllForceAct.triggered[()].connect(
+            self.__hgQueuePopAllPatchesForced)
+        self.actions.append(self.hgQueuePopAllForceAct)
+        
+        self.hgQueuePopUntilForceAct = E5Action(self.trUtf8('Pop Patches'),
+                self.trUtf8('Pop Patches'),
+                0, 0, self, 'mercurial_queues_pop_until_force')
+        self.hgQueuePopUntilForceAct.setStatusTip(self.trUtf8(
+            'Pop patches off the stack forgetting local changes'
+        ))
+        self.hgQueuePopUntilForceAct.setWhatsThis(self.trUtf8(
+            """<b>Pop Patches</b>"""
+            """<p>This pops patches off the stack of applied patches until a named"""
+            """ patch is at the top of the stack forgetting local changes.</p>"""
+        ))
+        self.hgQueuePopUntilForceAct.triggered[()].connect(self.__hgQueuePopPatchesForced)
+        self.actions.append(self.hgQueuePopUntilForceAct)
+    
+    def initMenu(self, mainMenu):
+        """
+        Public method to generate the VCS menu.
+        
+        @param mainMenu reference to the main menu (QMenu)
+        @return populated menu (QMenu)
+        """
+        menu = QMenu(self.trUtf8("Queues"), mainMenu)
+        
+        pushPopMenu = QMenu(self.trUtf8("Push/Pop"), menu)
+        pushPopMenu.addAction(self.hgQueuePushAct)
+        pushPopMenu.addAction(self.hgQueuePushUntilAct)
+        pushPopMenu.addAction(self.hgQueuePushAllAct)
+        pushPopMenu.addAction(self.hgQueuePopAct)
+        pushPopMenu.addAction(self.hgQueuePopUntilAct)
+        pushPopMenu.addAction(self.hgQueuePopAllAct)
+        
+        pushPopForceMenu = QMenu(self.trUtf8("Push/Pop (force)"), menu)
+        pushPopForceMenu.addAction(self.hgQueuePushForceAct)
+        pushPopForceMenu.addAction(self.hgQueuePushUntilForceAct)
+        pushPopForceMenu.addAction(self.hgQueuePushAllForceAct)
+        pushPopForceMenu.addAction(self.hgQueuePopForceAct)
+        pushPopForceMenu.addAction(self.hgQueuePopUntilForceAct)
+        pushPopForceMenu.addAction(self.hgQueuePopAllForceAct)
+        
+        menu.addAction(self.hgQueueNewAct)
+        menu.addAction(self.hgQueueRefreshAct)
+        menu.addAction(self.hgQueueFinishAct)
+        menu.addSeparator()
+        menu.addAction(self.hgQueueDiffAct)
+        menu.addSeparator()
+        menu.addAction(self.hgQueueListAct)
+        menu.addSeparator()
+        menu.addMenu(pushPopMenu)
+        menu.addMenu(pushPopForceMenu)
+        
+        return menu
+    
+    def __hgQueueNewPatch(self):
+        """
+        Private slot used to create a new named patch. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueueNewPatch(self.project.getProjectPath())
+    
+    def __hgQueueRefreshPatch(self):
+        """
+        Private slot used to refresh the current patch. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueueRefreshPatch(self.project.getProjectPath())
+    
+    def __hgQueueShowPatch(self):
+        """
+        Private slot used to show the contents of the current patch. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueueShowPatch(self.project.getProjectPath())
+    
+    def __hgQueuePushPatch(self):
+        """
+        Private slot used to push the next patch onto the stack. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=False, all=False, named=False)
+    
+    def __hgQueuePushPatchForced(self):
+        """
+        Private slot used to push the next patch onto the stack on top
+        of local changes. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=False, all=False, named=False, force=True)
+    
+    def __hgQueuePushAllPatches(self):
+        """
+        Private slot used to push all patches onto the stack. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=False, all=True, named=False)
+    
+    def __hgQueuePushAllPatchesForced(self):
+        """
+        Private slot used to push all patches onto the stack on top
+        of local changes. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=False, all=True, named=False, force=True)
+    
+    def __hgQueuePushPatches(self):
+        """
+        Private slot used to push patches onto the stack until a named
+        one is at the top. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=False, all=False, named=True)
+    
+    def __hgQueuePushPatchesForced(self):
+        """
+        Private slot used to push patches onto the stack until a named
+        one is at the top on top of local changes. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=False, all=False, named=True, force=True)
+    
+    def __hgQueuePopPatch(self):
+        """
+        Private slot used to pop the current patch off the stack. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=True, all=False, named=False)
+    
+    def __hgQueuePopPatchForced(self):
+        """
+        Private slot used to pop the current patch off the stack forgetting
+        any local changes to patched files. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=True, all=False, named=False)
+    
+    def __hgQueuePopAllPatches(self):
+        """
+        Private slot used to pop all patches off the stack. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=True, all=True, named=False)
+    
+    def __hgQueuePopAllPatchesForced(self):
+        """
+        Private slot used to pop all patches off the stack forgetting
+        any local changes to patched files. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=True, all=True, named=False, force=True)
+    
+    def __hgQueuePopPatches(self):
+        """
+        Private slot used to pop patches off the stack until a named
+        one is at the top. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=True, all=False, named=True)
+    
+    def __hgQueuePopPatchesForced(self):
+        """
+        Private slot used to pop patches off the stack until a named
+        one is at the top forgetting any local changes to patched files. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueuePushPopPatches(self.project.getProjectPath(), 
+                pop=True, all=False, named=True)
+    
+    def __hgQueueListPatches(self):
+        """
+        Private slot used to show a list of applied and unapplied patches. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueueListPatches(self.project.getProjectPath())
+    
+    def __hgQueueFinishAppliedPatches(self):
+        """
+        Private slot used to finish all applied patches. 
+        """
+        self.vcs.getExtensionObject("mq")\
+            .hgQueueFinishAppliedPatches(self.project.getProjectPath())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/__init__.py	Sat May 14 20:00:13 2011 +0200
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the queues extension support interface.
+"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/VcsPlugins/vcsMercurial/QueuesExtension/queues.py	Sat May 14 20:00:13 2011 +0200
@@ -0,0 +1,249 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the queues extension interface.
+"""
+import os
+
+from PyQt4.QtCore import QObject, QProcess
+from PyQt4.QtGui import QDialog, QApplication, QInputDialog
+
+from E5Gui import E5MessageBox
+
+from ..HgDialog import HgDialog
+from ..HgDiffDialog import HgDiffDialog
+
+from .HgQueuesNewPatchDialog import HgQueuesNewPatchDialog
+from .HgQueuesListDialog import HgQueuesListDialog
+
+import Preferences
+
+
+class Queues(QObject):
+    """
+    Class implementing the queues extension interface.
+    """
+    APPLIED_LIST = 0
+    UNAPPLIED_LIST = 1
+    SERIES_LIST = 2
+    
+    def __init__(self, vcs):
+        """
+        Constructor
+        """
+        QObject.__init__(self, vcs)
+        
+        self.vcs = vcs
+        
+        self.qdiffDialog = None
+    
+    def shutdown(self):
+        """
+        Public method used to shutdown the queues interface.
+        """
+        if self.qdiffDialog is not None:
+            self.qdiffDialog.close()
+    
+    def hgQueueNewPatch(self, name):
+        """
+        Public method to create a new named patch.
+        
+        @param name file/directory name (string)
+        """
+        # find the root of the repo
+        repodir = self.vcs.splitPath(name)[0]
+        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
+            repodir = os.path.dirname(repodir)
+            if repodir == os.sep:
+                return
+        
+        dlg = HgQueuesNewPatchDialog()
+        if dlg.exec_() == QDialog.Accepted:
+            name, message, (userData, currentUser, userName), \
+            (dateData, currentDate, dateStr) = dlg.getData()
+            
+            args = []
+            args.append("qnew")
+            if message != "":
+                args.append("--message")
+                args.append(message)
+            if userData:
+                if currentUser:
+                    args.append("--currentuser")
+                else:
+                    args.append("--user")
+                    args.append(userName)
+            if dateData:
+                if currentDate:
+                    args.append("--currentdate")
+                else:
+                    args.append("--date")
+                    args.append(dateStr)
+            args.append(name)
+            
+            dia = HgDialog(self.trUtf8('New Patch'))
+            res = dia.startProcess(args, repodir)
+            if res:
+                dia.exec_()
+                self.vcs.checkVCSStatus()
+    
+    def hgQueueRefreshPatch(self, name):
+        """
+        Public method to create a new named patch.
+        
+        @param name file/directory name (string)
+        """
+        # find the root of the repo
+        repodir = self.vcs.splitPath(name)[0]
+        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
+            repodir = os.path.dirname(repodir)
+            if repodir == os.sep:
+                return
+        
+        args = []
+        args.append("qrefresh")
+        
+        dia = HgDialog(self.trUtf8('Update Current Patch'))
+        res = dia.startProcess(args, repodir)
+        if res:
+            dia.exec_()
+            self.vcs.checkVCSStatus()
+    
+    def hgQueueShowPatch(self, name):
+        """
+        Public method to create a new named patch.
+        
+        @param name file/directory name (string)
+        """
+        self.qdiffDialog = HgDiffDialog(self.vcs)
+        self.qdiffDialog.show()
+        QApplication.processEvents()
+        self.qdiffDialog.start(name, qdiff=True)
+    
+    def hgQueuePushPopPatches(self, name, pop=False, all=False, named=False, force=False):
+        """
+        Public method to push patches onto the stack or pop patches off the stack.
+        
+        @param name file/directory name (string)
+        @keyparam pop flag indicating a pop action (boolean)
+        @keyparam all flag indicating to push/pop all (boolean)
+        @keyparam named flag indicating to push/pop until a named patch
+            is at the top of the stack (boolean)
+        @keyparam force flag indicating a forceful pop (boolean)
+        """
+        # find the root of the repo
+        repodir = self.vcs.splitPath(name)[0]
+        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
+            repodir = os.path.dirname(repodir)
+            if repodir == os.sep:
+                return
+        
+        args = []
+        if pop:
+            args.append("qpop")
+            title = self.trUtf8("Pop Patches")
+            listType = Queues.APPLIED_LIST
+        else:
+            args.append("qpush")
+            title = self.trUtf8("Push Patches")
+            listType = Queues.UNAPPLIED_LIST
+        if force:
+            args.append("--force")
+        if all:
+            args.append("--all")
+        elif named:
+            patchnames = self.__getUnAppliedPatches(repodir, listType)
+            if patchnames:
+                patch, ok = QInputDialog.getItem(
+                    None,
+                    self.trUtf8("Select Patch"),
+                    self.trUtf8("Select the target patch name:"),
+                    patchnames,
+                    0, False)
+                if ok and patch:
+                    args.append(patch)
+                else:
+                    return
+            else:
+                E5MessageBox.information(None,
+                    self.trUtf8("Select Patch"),
+                    self.trUtf8("""No patches to select from."""))
+                return
+        
+        dia = HgDialog(title)
+        res = dia.startProcess(args, repodir)
+        if res:
+            dia.exec_()
+            self.vcs.checkVCSStatus()
+    
+    def __getUnAppliedPatches(self, repodir, listType):
+        """
+        Public method to get the list of applied or unapplied patches.
+        
+        @param repodir directory name of the repository (string)
+        @param listType type of patcheslist to get
+            (Queues.APPLIED_LIST, Queues.UNAPPLIED_LIST, Queues.SERIES_LIST)
+        @return list of patches (list of string)
+        """
+        patchesList = []
+        
+        ioEncoding = Preferences.getSystem("IOEncoding")
+        process = QProcess()
+        args = []
+        if listType == Queues.APPLIED_LIST:
+            args.append("qapplied")
+        elif listType == Queues.UNAPPLIED_LIST:
+            args.append("qunapplied")
+        elif listType == Queues.SERIES_LIST:
+            args.append("qseries")
+        else:
+            raise ValueError("Illegal value for listType.")
+        
+        process.setWorkingDirectory(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')
+                for line in output.splitlines():
+                    patchesList.append(line.strip())
+        
+        return patchesList
+    
+    def hgQueueListPatches(self, name):
+        """
+        Public method to create a new named patch.
+        
+        @param name file/directory name (string)
+        """
+        self.queuesListDialog = HgQueuesListDialog(self.vcs)
+        self.queuesListDialog.show()
+        self.queuesListDialog.start(name)
+    
+    def hgQueueFinishAppliedPatches(self, name):
+        """
+        Public method to create a new named patch.
+        
+        @param name file/directory name (string)
+        """
+        # find the root of the repo
+        repodir = self.vcs.splitPath(name)[0]
+        while not os.path.isdir(os.path.join(repodir, self.vcs.adminDir)):
+            repodir = os.path.dirname(repodir)
+            if repodir == os.sep:
+                return
+        
+        args = []
+        args.append("qfinish")
+        args.append("--applied")
+        
+        dia = HgDialog(self.trUtf8('Finish Applied Patches'))
+        res = dia.startProcess(args, repodir)
+        if res:
+            dia.exec_()
+            self.vcs.checkVCSStatus()
--- a/Plugins/VcsPlugins/vcsMercurial/hg.py	Fri May 13 20:23:42 2011 +0200
+++ b/Plugins/VcsPlugins/vcsMercurial/hg.py	Sat May 14 20:00:13 2011 +0200
@@ -47,6 +47,7 @@
 from .HgUtilities import getConfigPath
 
 from .BookmarksExtension.bookmarks import Bookmarks
+from .QueuesExtension.queues import Queues
 
 from .ProjectBrowserHelper import HgProjectBrowserHelper
 
@@ -134,6 +135,7 @@
         # instantiate the extensions
         self.__extensions = {
             "bookmarks" : Bookmarks(self),
+            "mq" : Queues(self),
         }
     
     def getPlugin(self):
--- a/eric5.e4p	Fri May 13 20:23:42 2011 +0200
+++ b/eric5.e4p	Sat May 14 20:00:13 2011 +0200
@@ -883,6 +883,11 @@
     <Source>Plugins/VcsPlugins/vcsMercurial/BookmarksExtension/HgBookmarkDialog.py</Source>
     <Source>Plugins/VcsPlugins/vcsMercurial/BookmarksExtension/HgBookmarkRenameDialog.py</Source>
     <Source>Plugins/VcsPlugins/vcsMercurial/BookmarksExtension/HgBookmarksInOutDialog.py</Source>
+    <Source>Plugins/VcsPlugins/vcsMercurial/QueuesExtension/__init__.py</Source>
+    <Source>Plugins/VcsPlugins/vcsMercurial/QueuesExtension/queues.py</Source>
+    <Source>Plugins/VcsPlugins/vcsMercurial/QueuesExtension/ProjectHelper.py</Source>
+    <Source>Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesNewPatchDialog.py</Source>
+    <Source>Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.py</Source>
   </Sources>
   <Forms>
     <Form>PyUnit/UnittestDialog.ui</Form>
@@ -1126,6 +1131,8 @@
     <Form>Plugins/VcsPlugins/vcsMercurial/BookmarksExtension/HgBookmarkDialog.ui</Form>
     <Form>Plugins/VcsPlugins/vcsMercurial/BookmarksExtension/HgBookmarkRenameDialog.ui</Form>
     <Form>Plugins/VcsPlugins/vcsMercurial/BookmarksExtension/HgBookmarksInOutDialog.ui</Form>
+    <Form>Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesNewPatchDialog.ui</Form>
+    <Form>Plugins/VcsPlugins/vcsMercurial/QueuesExtension/HgQueuesListDialog.ui</Form>
   </Forms>
   <Translations>
     <Translation>i18n/eric5_cs.qm</Translation>

eric ide

mercurial