Tue, 25 Jun 2024 17:59:15 +0200
Modified the application execution dialog to allow the selection of a working directory.
--- 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):