HgDialog: extended the dialog to allow inputting user responses to client prompts.

Sat, 07 Mar 2020 17:22:14 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 07 Mar 2020 17:22:14 +0100
changeset 7441
f115f4469795
parent 7440
ea9c904def73
child 7442
ebcb3a228c3d

HgDialog: extended the dialog to allow inputting user responses to client prompts.

eric6/Plugins/VcsPlugins/vcsMercurial/HgClient.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsMercurial/HgDialog.py file | annotate | diff | comparison | revisions
eric6/Plugins/VcsPlugins/vcsMercurial/HgDialog.ui file | annotate | diff | comparison | revisions
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/HgClient.py	Sat Mar 07 13:03:19 2020 +0100
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/HgClient.py	Sat Mar 07 17:22:14 2020 +0100
@@ -33,10 +33,14 @@
         """
         Constructor
         
-        @param repoPath root directory of the repository (string)
-        @param encoding encoding to be used by the command server (string)
-        @param vcs reference to the VCS object (Hg)
-        @param parent reference to the parent object (QObject)
+        @param repoPath root directory of the repository
+        @type str
+        @param encoding encoding to be used by the command server
+        @type str
+        @param vcs reference to the VCS object
+        @type Hg
+        @param parent reference to the parent object
+        @type QObject
         """
         super(HgClient, self).__init__(parent)
         
@@ -69,8 +73,9 @@
         """
         Public method to start the command server.
         
-        @return tuple of flag indicating a successful start (boolean) and
-            an error message (string) in case of failure
+        @return tuple of flag indicating a successful start and an error
+            message in case of failure
+        @rtype tuple of (bool, str)
         """
         self.__server = QProcess()
         self.__server.setWorkingDirectory(self.__repoPath)
@@ -115,8 +120,9 @@
         """
         Public method to restart the command server.
         
-        @return tuple of flag indicating a successful start (boolean) and
-            an error message (string) in case of failure
+        @return tuple of flag indicating a successful start and an error
+            message in case of failure
+        @rtype tuple of (bool, str)
         """
         self.stopServer()
         return self.startServer()
@@ -125,8 +131,9 @@
         """
         Private method to read the hello message sent by the command server.
         
-        @return tuple of flag indicating success (boolean) and an error message
-            in case of failure (string)
+        @return tuple of flag indicating success and an error message in case
+            of failure
+        @rtype tuple of (bool, str)
         """
         ch, msg = self.__readChannel()
         if not ch:
@@ -165,8 +172,10 @@
         """
         Private slot connected to the finished signal.
         
-        @param exitCode exit code of the process (integer)
-        @param exitStatus exit status of the process (QProcess.ExitStatus)
+        @param exitCode exit code of the process
+        @type int
+        @param exitStatus exit status of the process
+        @type QProcess.ExitStatus
         """
         self.__started = False
     
@@ -175,7 +184,7 @@
         Private method to read data from the command server.
         
         @return tuple of channel designator and channel data
-            (string, integer or string or bytes)
+        @rtype tuple of (str, int or str or bytes)
         """
         if (
             self.__server.bytesAvailable() > 0 or
@@ -209,7 +218,8 @@
         """
         Private slot to write some data to the command server.
         
-        @param data data to be sent (string)
+        @param data data to be sent
+        @type str
         """
         if not isinstance(data, bytes):
             data = data.encode(self.__encoding)
@@ -222,15 +232,19 @@
         """
         Private method to run a command in the server (low level).
         
-        @param args list of arguments for the command (list of string)
+        @param args list of arguments for the command
+        @type list of str
         @param inputChannels dictionary of input channels. The dictionary must
             have the keys 'I' and 'L' and each entry must be a function
             receiving the number of bytes to write.
+        @type dict
         @param outputChannels dictionary of output channels. The dictionary
             must have the keys 'o' and 'e' and each entry must be a function
             receiving the data.
+        @type dict
         @return result code of the command, -1 if the command server wasn't
-            started or -10, if the command was canceled (integer)
+            started or -10, if the command was canceled
+        @rtype int
         @exception RuntimeError raised to indicate an unexpected command
             channel
         """
@@ -286,9 +300,13 @@
         """
         Private method to prompt the user for some input.
         
-        @param size maximum length of the requested input (integer)
-        @param message message sent by the server (string)
-        @return data entered by the user (string)
+        @param size maximum length of the requested input
+        @type int
+        @param message message sent by the server
+        @type str
+        @return tuple containing data entered by the user and
+            a flag indicating a password input
+        @rtype tuple of (str, bool)
         """
         from .HgClientPromptDialog import HgClientPromptDialog
         inputData = ""
@@ -304,19 +322,28 @@
         """
         Public method to execute a command via the command server.
         
-        @param args list of arguments for the command (list of string)
-        @keyparam prompt function to reply to prompts by the server. It
+        @param args list of arguments for the command
+        @type list of str
+        @param prompt function to reply to prompts by the server. It
             receives the max number of bytes to return and the contents
-            of the output channel received so far.
-        @keyparam inputData function to reply to bulk data requests by the
+            of the output channel received so far. If an output function is
+            given as well, the prompt data is passed through the output
+            function. The function must return the input data and a flag
+            indicating a password input.
+        @type func(int, str) -> (str, bool)
+        @param inputData function to reply to bulk data requests by the
             server. It receives the max number of bytes to return.
-        @keyparam output function receiving the data from the server (string).
-            If a prompt function is given, this parameter will be ignored.
-        @keyparam error function receiving error messages from the server
-            (string)
-        @return output and errors of the command server (string). In case
+        @type func(int) -> bytes
+        @param output function receiving the data from the server. If a
+            prompt function is given, it is assumed, that the prompt output
+            is passed via this function.
+        @type func(str)
+        @param error function receiving error messages from the server
+        @type func(str)
+        @return tuple of output and errors of the command server. In case
             output and/or error functions were given, the respective return
             value will be an empty string.
+        @rtype tuple of (str, str)
         """
         if not self.__started:
             # try to start the Mercurial command server
@@ -329,7 +356,7 @@
         outputBuffer = None
         errorBuffer = None
         
-        if prompt is not None or output is None:
+        if output is None:
             outputBuffer = io.StringIO()
             outputChannels["o"] = outputBuffer.write
         else:
@@ -343,8 +370,12 @@
         inputChannels = {}
         if prompt is not None:
             def func(size):
-                reply = prompt(size, outputBuffer.getvalue())
-                return reply, False
+                if outputBuffer is None:
+                    msg = ""
+                else:
+                    msg = outputBuffer.getvalue()
+                reply, isPassword = prompt(size, msg)
+                return reply, isPassword
             inputChannels["L"] = func
         else:
             def myprompt(size):
@@ -384,7 +415,8 @@
         """
         Public method to check, if the last command was canceled.
         
-        @return flag indicating the cancel state (boolean)
+        @return flag indicating the cancel state
+        @rtype bool
         """
         return self.__cancel
     
@@ -392,7 +424,8 @@
         """
         Public method to check, if the server is executing a command.
         
-        @return flag indicating the execution of a command (boolean)
+        @return flag indicating the execution of a command
+        @rtype bool
         """
         return self.__commandRunning
 
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/HgDialog.py	Sat Mar 07 13:03:19 2020 +0100
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/HgDialog.py	Sat Mar 07 17:22:14 2020 +0100
@@ -92,6 +92,7 @@
         @return flag indicating a successful start of the process
         """
         self.errorGroup.hide()
+        self.inputGroup.hide()
         self.normal = False
         
         self.__hasAddOrDelete = False
@@ -111,7 +112,11 @@
             self.resultbox.append('')
         
         out, err = self.vcs.getClient().runcommand(
-            args, output=self.__showOutput, error=self.__showError)
+            args,
+            prompt=self.__getInput,
+            output=self.__showOutput,
+            error=self.__showError
+        )
         
         if err:
             self.__showError(err)
@@ -178,3 +183,31 @@
         @return flag indicating the presence of an add or delete (boolean)
         """
         return self.__hasAddOrDelete
+    
+    def __getInput(self, size, message):
+        """
+        Private method to get some input from the user.
+        
+        @param size maximum length of the requested input
+        @type int
+        @param message message sent by the server
+        @type str
+        @return tuple containing data entered by the user and
+            a flag indicating a password input
+        @rtype tuple of (str, bool)
+        """
+        self.inputGroup.show()
+        self.input.setMaxLength(size)
+        self.input.setFocus(Qt.OtherFocusReason)
+        
+        from PyQt5.QtCore import QEventLoop
+        loop = QEventLoop(self)
+        self.sendButton.clicked[bool].connect(loop.quit)
+        loop.exec_()
+        message = self.input.text() + "\n"
+        isPassword = self.passwordCheckBox.isChecked()
+        
+        self.input.clear()
+        self.inputGroup.hide()
+        
+        return message, isPassword
--- a/eric6/Plugins/VcsPlugins/vcsMercurial/HgDialog.ui	Sat Mar 07 13:03:19 2020 +0100
+++ b/eric6/Plugins/VcsPlugins/vcsMercurial/HgDialog.ui	Sat Mar 07 17:22:14 2020 +0100
@@ -16,7 +16,7 @@
   <property name="sizeGripEnabled">
    <bool>true</bool>
   </property>
-  <layout class="QVBoxLayout">
+  <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QGroupBox" name="outputGroup">
      <property name="sizePolicy">
@@ -68,6 +68,64 @@
     </widget>
    </item>
    <item>
+    <widget class="QGroupBox" name="inputGroup">
+     <property name="title">
+      <string>Input</string>
+     </property>
+     <layout class="QGridLayout" name="_2">
+      <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 subversion 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 subversion 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>
@@ -83,7 +141,9 @@
  <tabstops>
   <tabstop>resultbox</tabstop>
   <tabstop>errors</tabstop>
-  <tabstop>buttonBox</tabstop>
+  <tabstop>passwordCheckBox</tabstop>
+  <tabstop>input</tabstop>
+  <tabstop>sendButton</tabstop>
  </tabstops>
  <resources/>
  <connections/>

eric ide

mercurial