Modified the application execution dialog to allow the selection of a working directory.

Tue, 25 Jun 2024 17:59:15 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 25 Jun 2024 17:59:15 +0200
changeset 7
9a98f7260372
parent 6
e6c86dad1317
child 8
02b45cd11e64

Modified the application execution dialog to allow the selection of a working directory.

PipxInterface/PipxAppStartDialog.py file | annotate | diff | comparison | revisions
PipxInterface/PipxAppStartDialog.ui file | annotate | diff | comparison | revisions
PipxInterface/PipxWidget.py file | annotate | diff | comparison | revisions
PipxInterface/Ui_PipxAppStartDialog.py file | annotate | diff | comparison | revisions
PluginPipxInterface.epj file | annotate | diff | comparison | revisions
PluginPipxInterface.py file | annotate | diff | comparison | revisions
--- a/PipxInterface/PipxAppStartDialog.py	Tue Jun 25 17:58:25 2024 +0200
+++ b/PipxInterface/PipxAppStartDialog.py	Tue Jun 25 17:59:15 2024 +0200
@@ -9,11 +9,12 @@
 import shlex
 
 from PyQt6.QtCore import QCoreApplication, QProcess, Qt, QTimer, pyqtSlot
-from PyQt6.QtWidgets import QAbstractButton, QDialog, QDialogButtonBox
+from PyQt6.QtWidgets import QAbstractButton, QComboBox, QDialog, QDialogButtonBox
 
 from eric7 import Preferences
 from eric7.EricGui import EricPixmapCache
 from eric7.EricWidgets import EricMessageBox
+from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
 
 from .Ui_PipxAppStartDialog import Ui_PipxAppStartDialog
 
@@ -24,12 +25,14 @@
     to execute the app.
     """
 
-    def __init__(self, app, parent=None):
+    def __init__(self, app, plugin, parent=None):
         """
         Constructor
 
         @param app path of the application to be executed
         @type str
+        @param plugin reference to the plug-in object
+        @type PluginPipxInterface
         @param parent reference to the parent widget (defaults to None)
         @type QWidget (optional)
         """
@@ -38,11 +41,18 @@
 
         self.executeButton.setIcon(EricPixmapCache.getIcon("start"))
 
+        self.workdirPicker.setMode(EricPathPickerModes.DIRECTORY_MODE)
+        self.workdirPicker.setInsertPolicy(QComboBox.InsertPolicy.InsertAtTop)
+
+        self.__plugin = plugin
+
         self.__process = None
 
         self.appLabel.setText(app)
         self.errorGroup.hide()
 
+        self.__populateWorkDirs()
+
         self.parametersEdit.returnPressed.connect(self.on_executeButton_clicked)
 
     def closeEvent(self, e):
@@ -117,6 +127,12 @@
         self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setEnabled(True)
         self.executeButton.setEnabled(False)
 
+        # clear output of last run
+        self.resultbox.clear()
+        self.errors.clear()
+        self.errorGroup.hide()
+
+        workdir = self.workdirPicker.text()
         command = self.parametersEdit.text()
         args = shlex.split(command)
 
@@ -124,6 +140,9 @@
         self.__process.finished.connect(self.__procFinished)
         self.__process.readyReadStandardOutput.connect(self.__readStdout)
         self.__process.readyReadStandardError.connect(self.__readStderr)
+        if os.path.isdir(workdir) or workdir == "":
+            self.__populateWorkDirs(workdir)
+            self.__process.setWorkingDirectory(workdir)
         self.__process.start(self.appLabel.text(), args)
         procStarted = self.__process.waitForStarted(5000)
         if not procStarted:
@@ -180,3 +199,26 @@
             self.errors.ensureCursorVisible()
 
             QCoreApplication.processEvents()
+
+    def __populateWorkDirs(self, mostRecent=None):
+        """
+        Private method to populate the working directory selector.
+
+        @param mostRecent most recently used working directory
+        @type str
+        """
+        workDirList = self.__plugin.getPreferences("RecentAppWorkdirs")
+        if mostRecent is not None:
+            if mostRecent in workDirList:
+                # push it to the beginning of the list
+                workDirList.remove(mostRecent)
+            workDirList.insert(0, mostRecent)
+            workDirList = workDirList[
+                : self.__plugin.getPreferences("MaxRecentAppWorkdirs")
+            ]
+            self.__plugin.setPreferences("RecentAppWorkdirs", workDirList)
+
+        self.workdirPicker.clear()
+        self.workdirPicker.addItems(workDirList)
+        if len(workDirList) > 0:
+            self.workdirPicker.setCurrentIndex(0)
--- a/PipxInterface/PipxAppStartDialog.ui	Tue Jun 25 17:58:25 2024 +0200
+++ b/PipxInterface/PipxAppStartDialog.ui	Tue Jun 25 17:59:15 2024 +0200
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>600</width>
-    <height>700</height>
+    <height>800</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -16,32 +16,106 @@
   <property name="sizeGripEnabled">
    <bool>true</bool>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout_2">
+  <layout class="QVBoxLayout" name="verticalLayout_3">
    <item>
     <widget class="QLabel" name="appLabel"/>
    </item>
    <item>
     <widget class="QGroupBox" name="groupBox">
      <property name="title">
-      <string>Command Line Parameters</string>
+      <string>Execution Parameters</string>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout">
       <item>
-       <widget class="QLineEdit" name="parametersEdit">
-        <property name="toolTip">
-         <string>Enter the command line parameters for the application.</string>
-        </property>
-        <property name="clearButtonEnabled">
-         <bool>true</bool>
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>Command Line Parameters:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLineEdit" name="parametersEdit">
+          <property name="toolTip">
+           <string>Enter the command line parameters for the application.</string>
+          </property>
+          <property name="clearButtonEnabled">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QLabel" name="label_2">
+          <property name="text">
+           <string>Working Directory:</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="EricComboPathPicker" name="workdirPicker" native="true">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="focusPolicy">
+           <enum>Qt::WheelFocus</enum>
+          </property>
+          <property name="toolTip">
+           <string>Enter the working directory for the application run.</string>
+          </property>
+          <property name="whatsThis">
+           <string/>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="Line" name="line">
+        <property name="orientation">
+         <enum>Qt::Vertical</enum>
         </property>
        </widget>
       </item>
       <item>
-       <widget class="QToolButton" name="executeButton">
-        <property name="toolTip">
-         <string>Press to execute the application with the entered parameters.</string>
-        </property>
-       </widget>
+       <layout class="QVBoxLayout" name="verticalLayout_2">
+        <item>
+         <spacer name="verticalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item>
+         <widget class="QToolButton" name="executeButton">
+          <property name="toolTip">
+           <string>Press to execute the application with the entered parameters.</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer name="verticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
       </item>
      </layout>
     </widget>
@@ -110,8 +184,17 @@
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+ <customwidgets>
+  <customwidget>
+   <class>EricComboPathPicker</class>
+   <extends>QWidget</extends>
+   <header>eric7/EricWidgets/EricPathPicker.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
  <tabstops>
   <tabstop>parametersEdit</tabstop>
+  <tabstop>workdirPicker</tabstop>
   <tabstop>executeButton</tabstop>
   <tabstop>resultbox</tabstop>
   <tabstop>errors</tabstop>
--- a/PipxInterface/PipxWidget.py	Tue Jun 25 17:58:25 2024 +0200
+++ b/PipxInterface/PipxWidget.py	Tue Jun 25 17:59:15 2024 +0200
@@ -44,6 +44,7 @@
         super().__init__(parent)
         self.setupUi(self)
 
+        self.__plugin = plugin
         self.__pipx = Pipx(self)
 
         if fromEric:
@@ -135,5 +136,5 @@
         """
         if item.parent() is not None:
             app = item.data(0, PipxWidget.AppPathRole)
-            dlg = PipxAppStartDialog(app, self)
+            dlg = PipxAppStartDialog(app, self.__plugin, self)
             dlg.show()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PipxInterface/Ui_PipxAppStartDialog.py	Tue Jun 25 17:59:15 2024 +0200
@@ -0,0 +1,129 @@
+# Form implementation generated from reading ui file 'PipxInterface/PipxAppStartDialog.ui'
+#
+# Created by: PyQt6 UI code generator 6.7.0
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic6 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt6 import QtCore, QtGui, QtWidgets
+
+
+class Ui_PipxAppStartDialog(object):
+    def setupUi(self, PipxAppStartDialog):
+        PipxAppStartDialog.setObjectName("PipxAppStartDialog")
+        PipxAppStartDialog.resize(600, 800)
+        PipxAppStartDialog.setWindowTitle("Start Application")
+        PipxAppStartDialog.setSizeGripEnabled(True)
+        self.verticalLayout_3 = QtWidgets.QVBoxLayout(PipxAppStartDialog)
+        self.verticalLayout_3.setContentsMargins(11, 11, 11, 11)
+        self.verticalLayout_3.setSpacing(6)
+        self.verticalLayout_3.setObjectName("verticalLayout_3")
+        self.appLabel = QtWidgets.QLabel(parent=PipxAppStartDialog)
+        self.appLabel.setObjectName("appLabel")
+        self.verticalLayout_3.addWidget(self.appLabel)
+        self.groupBox = QtWidgets.QGroupBox(parent=PipxAppStartDialog)
+        self.groupBox.setObjectName("groupBox")
+        self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox)
+        self.horizontalLayout.setContentsMargins(11, 11, 11, 11)
+        self.horizontalLayout.setSpacing(6)
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.verticalLayout = QtWidgets.QVBoxLayout()
+        self.verticalLayout.setSpacing(6)
+        self.verticalLayout.setObjectName("verticalLayout")
+        self.label = QtWidgets.QLabel(parent=self.groupBox)
+        self.label.setObjectName("label")
+        self.verticalLayout.addWidget(self.label)
+        self.parametersEdit = QtWidgets.QLineEdit(parent=self.groupBox)
+        self.parametersEdit.setClearButtonEnabled(True)
+        self.parametersEdit.setObjectName("parametersEdit")
+        self.verticalLayout.addWidget(self.parametersEdit)
+        self.label_2 = QtWidgets.QLabel(parent=self.groupBox)
+        self.label_2.setObjectName("label_2")
+        self.verticalLayout.addWidget(self.label_2)
+        self.workdirPicker = EricComboPathPicker(parent=self.groupBox)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.workdirPicker.sizePolicy().hasHeightForWidth())
+        self.workdirPicker.setSizePolicy(sizePolicy)
+        self.workdirPicker.setFocusPolicy(QtCore.Qt.FocusPolicy.WheelFocus)
+        self.workdirPicker.setWhatsThis("")
+        self.workdirPicker.setObjectName("workdirPicker")
+        self.verticalLayout.addWidget(self.workdirPicker)
+        self.horizontalLayout.addLayout(self.verticalLayout)
+        self.line = QtWidgets.QFrame(parent=self.groupBox)
+        self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine)
+        self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
+        self.line.setObjectName("line")
+        self.horizontalLayout.addWidget(self.line)
+        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
+        self.verticalLayout_2.setSpacing(6)
+        self.verticalLayout_2.setObjectName("verticalLayout_2")
+        spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
+        self.verticalLayout_2.addItem(spacerItem)
+        self.executeButton = QtWidgets.QToolButton(parent=self.groupBox)
+        self.executeButton.setObjectName("executeButton")
+        self.verticalLayout_2.addWidget(self.executeButton)
+        spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
+        self.verticalLayout_2.addItem(spacerItem1)
+        self.horizontalLayout.addLayout(self.verticalLayout_2)
+        self.verticalLayout_3.addWidget(self.groupBox)
+        self.outputGroup = QtWidgets.QGroupBox(parent=PipxAppStartDialog)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(3)
+        sizePolicy.setHeightForWidth(self.outputGroup.sizePolicy().hasHeightForWidth())
+        self.outputGroup.setSizePolicy(sizePolicy)
+        self.outputGroup.setObjectName("outputGroup")
+        self.vboxlayout = QtWidgets.QVBoxLayout(self.outputGroup)
+        self.vboxlayout.setContentsMargins(11, 11, 11, 11)
+        self.vboxlayout.setSpacing(6)
+        self.vboxlayout.setObjectName("vboxlayout")
+        self.resultbox = QtWidgets.QTextEdit(parent=self.outputGroup)
+        self.resultbox.setReadOnly(True)
+        self.resultbox.setAcceptRichText(False)
+        self.resultbox.setObjectName("resultbox")
+        self.vboxlayout.addWidget(self.resultbox)
+        self.verticalLayout_3.addWidget(self.outputGroup)
+        self.errorGroup = QtWidgets.QGroupBox(parent=PipxAppStartDialog)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(1)
+        sizePolicy.setHeightForWidth(self.errorGroup.sizePolicy().hasHeightForWidth())
+        self.errorGroup.setSizePolicy(sizePolicy)
+        self.errorGroup.setObjectName("errorGroup")
+        self.vboxlayout1 = QtWidgets.QVBoxLayout(self.errorGroup)
+        self.vboxlayout1.setContentsMargins(11, 11, 11, 11)
+        self.vboxlayout1.setSpacing(6)
+        self.vboxlayout1.setObjectName("vboxlayout1")
+        self.errors = QtWidgets.QTextEdit(parent=self.errorGroup)
+        self.errors.setReadOnly(True)
+        self.errors.setAcceptRichText(False)
+        self.errors.setObjectName("errors")
+        self.vboxlayout1.addWidget(self.errors)
+        self.verticalLayout_3.addWidget(self.errorGroup)
+        self.buttonBox = QtWidgets.QDialogButtonBox(parent=PipxAppStartDialog)
+        self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
+        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Close)
+        self.buttonBox.setObjectName("buttonBox")
+        self.verticalLayout_3.addWidget(self.buttonBox)
+
+        self.retranslateUi(PipxAppStartDialog)
+        QtCore.QMetaObject.connectSlotsByName(PipxAppStartDialog)
+        PipxAppStartDialog.setTabOrder(self.parametersEdit, self.workdirPicker)
+        PipxAppStartDialog.setTabOrder(self.workdirPicker, self.executeButton)
+        PipxAppStartDialog.setTabOrder(self.executeButton, self.resultbox)
+        PipxAppStartDialog.setTabOrder(self.resultbox, self.errors)
+
+    def retranslateUi(self, PipxAppStartDialog):
+        _translate = QtCore.QCoreApplication.translate
+        self.groupBox.setTitle(_translate("PipxAppStartDialog", "Execution Parameters"))
+        self.label.setText(_translate("PipxAppStartDialog", "Command Line Parameters:"))
+        self.parametersEdit.setToolTip(_translate("PipxAppStartDialog", "Enter the command line parameters for the application."))
+        self.label_2.setText(_translate("PipxAppStartDialog", "Working Directory:"))
+        self.workdirPicker.setToolTip(_translate("PipxAppStartDialog", "Enter the working directory for the application run."))
+        self.executeButton.setToolTip(_translate("PipxAppStartDialog", "Press to execute the application with the entered parameters."))
+        self.outputGroup.setTitle(_translate("PipxAppStartDialog", "Output"))
+        self.errorGroup.setTitle(_translate("PipxAppStartDialog", "Errors"))
+from eric7.EricWidgets.EricPathPicker import EricComboPathPicker
--- a/PluginPipxInterface.epj	Tue Jun 25 17:58:25 2024 +0200
+++ b/PluginPipxInterface.epj	Tue Jun 25 17:59:15 2024 +0200
@@ -39,6 +39,7 @@
       "makefile": "OTHERS"
     },
     "FORMS": [
+      "PipxInterface/PipxAppStartDialog.ui",
       "PipxInterface/PipxDialog.ui",
       "PipxInterface/PipxWidget.ui"
     ],
@@ -124,8 +125,10 @@
     "RESOURCES": [],
     "SOURCES": [
       "PipxInterface/Pipx.py",
+      "PipxInterface/PipxAppStartDialog.py",
       "PipxInterface/PipxDialog.py",
       "PipxInterface/PipxWidget.py",
+      "PipxInterface/Ui_PipxAppStartDialog.py",
       "PipxInterface/Ui_PipxDialog.py",
       "PipxInterface/Ui_PipxWidget.py",
       "PipxInterface/__init__.py",
--- a/PluginPipxInterface.py	Tue Jun 25 17:58:25 2024 +0200
+++ b/PluginPipxInterface.py	Tue Jun 25 17:59:15 2024 +0200
@@ -13,7 +13,7 @@
 from PyQt6.QtCore import QCoreApplication, QObject, Qt, QTranslator
 from PyQt6.QtGui import QKeySequence
 
-from eric7 import Preferences
+from eric7 import Globals, Preferences
 from eric7.EricGui import EricPixmapCache
 from eric7.EricGui.EricAction import EricAction
 from eric7.EricWidgets.EricApplication import ericApp
@@ -148,6 +148,8 @@
 
         self.__defaults = {
             # TODO: fill this dictionary with preferences default values
+            "RecentAppWorkdirs": [],
+            "MaxRecentAppWorkdirs": 20,
         }
 
         self.__translator = None
@@ -266,6 +268,19 @@
         @return the requested setting value
         @rtype Any
         """
+        if key in ("RecentAppWorkdirs",):
+            return Globals.toList(
+                Preferences.Prefs.settings.value(
+                    self.PreferencesKey + "/" + key, self.__defaults[key]
+                )
+            )
+        elif key in ("MaxRecentAppWorkdirs",):
+            return int(
+                Preferences.Prefs.settings.value(
+                    self.PreferencesKey + "/" + key, self.__defaults[key]
+                )
+            )
+
         return None
 
     def setPreferences(self, key, value):
@@ -277,7 +292,7 @@
         @param value the value to be set
         @type Any
         """
-        pass
+        Preferences.Prefs.settings.setValue(self.PreferencesKey + "/" + key, value)
 
 
 def installDependencies(pipInstall):

eric ide

mercurial