|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2018 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a dialog to enter the data of a virtual environment. |
|
8 """ |
|
9 |
|
10 import os |
|
11 import sys |
|
12 |
|
13 from PyQt5.QtCore import pyqtSlot, Qt |
|
14 from PyQt5.QtWidgets import QDialog, QDialogButtonBox |
|
15 |
|
16 from E5Gui.E5PathPicker import E5PathPickerModes |
|
17 |
|
18 from .Ui_VirtualenvAddEditDialog import Ui_VirtualenvAddEditDialog |
|
19 |
|
20 import Utilities |
|
21 |
|
22 |
|
23 class VirtualenvAddEditDialog(QDialog, Ui_VirtualenvAddEditDialog): |
|
24 """ |
|
25 Class implementing a dialog to enter the data of a virtual environment. |
|
26 """ |
|
27 def __init__(self, manager, venvName="", venvDirectory="", |
|
28 venvInterpreter="", isGlobal=False, isConda=False, |
|
29 isRemote=False, execPath="", baseDir="", parent=None): |
|
30 """ |
|
31 Constructor |
|
32 |
|
33 @param manager reference to the virtual environment manager |
|
34 @type VirtualenvManager |
|
35 @param venvName logical name of a virtual environment for editing |
|
36 @type str |
|
37 @param venvDirectory directory of the virtual environment |
|
38 @type str |
|
39 @param venvInterpreter Python interpreter of the virtual environment |
|
40 @type str |
|
41 @param isGlobal flag indicating a global environment |
|
42 @type bool |
|
43 @param isConda flag indicating an Anaconda virtual environment |
|
44 @type bool |
|
45 @param isRemote flag indicating a remotely accessed environment |
|
46 @type bool |
|
47 @param execPath search path string to be prepended to the PATH |
|
48 environment variable |
|
49 @type str |
|
50 @param baseDir base directory for the virtual environments |
|
51 @type str |
|
52 @param parent reference to the parent widget |
|
53 @type QWidget |
|
54 """ |
|
55 super().__init__(parent) |
|
56 self.setupUi(self) |
|
57 |
|
58 self.__venvName = venvName |
|
59 self.__manager = manager |
|
60 self.__editMode = bool(venvName) |
|
61 |
|
62 if self.__editMode: |
|
63 self.setWindowTitle(self.tr("Edit Virtual Environment")) |
|
64 else: |
|
65 self.setWindowTitle(self.tr("Add Virtual Environment")) |
|
66 |
|
67 self.__envBaseDir = baseDir |
|
68 if not self.__envBaseDir: |
|
69 self.__envBaseDir = Utilities.getHomeDir() |
|
70 |
|
71 self.targetDirectoryPicker.setMode(E5PathPickerModes.DirectoryMode) |
|
72 self.targetDirectoryPicker.setWindowTitle( |
|
73 self.tr("Virtualenv Target Directory")) |
|
74 self.targetDirectoryPicker.setDefaultDirectory(self.__envBaseDir) |
|
75 |
|
76 self.pythonExecPicker.setMode(E5PathPickerModes.OpenFileMode) |
|
77 self.pythonExecPicker.setWindowTitle( |
|
78 self.tr("Python Interpreter")) |
|
79 self.pythonExecPicker.setDefaultDirectory( |
|
80 sys.executable.replace("w.exe", ".exe")) |
|
81 |
|
82 self.execPathEdit.setToolTip(self.tr( |
|
83 "Enter the executable search path to be prepended to the PATH" |
|
84 " environment variable. Use '{0}' as the separator.").format( |
|
85 os.pathsep) |
|
86 ) |
|
87 |
|
88 self.nameEdit.setText(venvName) |
|
89 if venvName: |
|
90 self.targetDirectoryPicker.setText(venvDirectory, |
|
91 toNative=not isRemote) |
|
92 else: |
|
93 self.targetDirectoryPicker.setText(self.__envBaseDir, |
|
94 toNative=not isRemote) |
|
95 self.pythonExecPicker.setText(venvInterpreter, |
|
96 toNative=not isRemote) |
|
97 self.globalCheckBox.setChecked(isGlobal) |
|
98 self.anacondaCheckBox.setChecked(isConda) |
|
99 self.remoteCheckBox.setChecked(isRemote) |
|
100 self.execPathEdit.setText(execPath) |
|
101 |
|
102 self.__updateOk() |
|
103 |
|
104 self.nameEdit.setFocus(Qt.FocusReason.OtherFocusReason) |
|
105 |
|
106 def __updateOk(self): |
|
107 """ |
|
108 Private slot to update the state of the OK button. |
|
109 """ |
|
110 enable = ( |
|
111 (bool(self.nameEdit.text()) and |
|
112 (self.nameEdit.text() == self.__venvName or |
|
113 self.__manager.isUnique(self.nameEdit.text()))) |
|
114 if self.__editMode else |
|
115 (bool(self.nameEdit.text()) and |
|
116 self.__manager.isUnique(self.nameEdit.text())) |
|
117 ) |
|
118 |
|
119 if not self.globalCheckBox.isChecked(): |
|
120 enable &= ( |
|
121 self.remoteCheckBox.isChecked() or ( |
|
122 bool(self.targetDirectoryPicker.text()) and |
|
123 self.targetDirectoryPicker.text() != self.__envBaseDir and |
|
124 os.path.exists(self.targetDirectoryPicker.text()) |
|
125 ) |
|
126 ) |
|
127 |
|
128 enable = ( |
|
129 enable and |
|
130 bool(self.pythonExecPicker.text()) and ( |
|
131 self.remoteCheckBox.isChecked() or |
|
132 os.access(self.pythonExecPicker.text(), os.X_OK) |
|
133 ) |
|
134 ) |
|
135 |
|
136 self.buttonBox.button( |
|
137 QDialogButtonBox.StandardButton.Ok).setEnabled(enable) |
|
138 |
|
139 @pyqtSlot(str) |
|
140 def on_nameEdit_textChanged(self, txt): |
|
141 """ |
|
142 Private slot to handle changes of the logical name. |
|
143 |
|
144 @param txt current logical name |
|
145 @type str |
|
146 """ |
|
147 self.__updateOk() |
|
148 |
|
149 @pyqtSlot(str) |
|
150 def on_targetDirectoryPicker_textChanged(self, txt): |
|
151 """ |
|
152 Private slot to handle changes of the virtual environment directory. |
|
153 |
|
154 @param txt virtual environment directory |
|
155 @type str |
|
156 """ |
|
157 self.__updateOk() |
|
158 |
|
159 if txt: |
|
160 self.pythonExecPicker.setDefaultDirectory(txt) |
|
161 else: |
|
162 self.pythonExecPicker.setDefaultDirectory( |
|
163 sys.executable.replace("w.exe", ".exe")) |
|
164 |
|
165 @pyqtSlot(str) |
|
166 def on_pythonExecPicker_textChanged(self, txt): |
|
167 """ |
|
168 Private slot to handle changes of the virtual environment interpreter. |
|
169 |
|
170 @param txt virtual environment interpreter |
|
171 @type str |
|
172 """ |
|
173 self.__updateOk() |
|
174 |
|
175 @pyqtSlot(bool) |
|
176 def on_globalCheckBox_toggled(self, checked): |
|
177 """ |
|
178 Private slot handling a change of the global check box state. |
|
179 |
|
180 @param checked state of the check box |
|
181 @type bool |
|
182 """ |
|
183 self.__updateOk() |
|
184 |
|
185 @pyqtSlot(bool) |
|
186 def on_remoteCheckBox_toggled(self, checked): |
|
187 """ |
|
188 Private slot handling a change of the remote check box state. |
|
189 |
|
190 @param checked state of the check box |
|
191 @type bool |
|
192 """ |
|
193 self.__updateOk() |
|
194 |
|
195 @pyqtSlot(bool) |
|
196 def on_anacondaCheckBox_clicked(self, checked): |
|
197 """ |
|
198 Private slot handling a user click on this check box. |
|
199 |
|
200 @param checked state of the check box |
|
201 @type bool |
|
202 """ |
|
203 if checked and not bool(self.execPathEdit.text()): |
|
204 # prepopulate the execPathEdit widget |
|
205 if Utilities.isWindowsPlatform(): |
|
206 self.execPathEdit.setText(os.pathsep.join([ |
|
207 self.targetDirectoryPicker.text(), |
|
208 os.path.join(self.targetDirectoryPicker.text(), |
|
209 "Scripts"), |
|
210 os.path.join(self.targetDirectoryPicker.text(), |
|
211 "Library", "bin"), |
|
212 ])) |
|
213 else: |
|
214 self.execPathEdit.setText( |
|
215 os.path.join(self.targetDirectoryPicker.text(), |
|
216 "bin"), |
|
217 ) |
|
218 |
|
219 def getData(self): |
|
220 """ |
|
221 Public method to retrieve the entered data. |
|
222 |
|
223 @return tuple containing the logical name, the directory, the |
|
224 interpreter of the virtual environment, a flag indicating a |
|
225 global environment, a flag indicating an Anaconda environment, |
|
226 a flag indicating a remotely accessed environment and a string |
|
227 to be prepended to the PATH environment variable |
|
228 @rtype tuple of (str, str, str, bool, bool, bool, str) |
|
229 """ |
|
230 nativePaths = not self.remoteCheckBox.isChecked() |
|
231 return ( |
|
232 self.nameEdit.text(), |
|
233 self.targetDirectoryPicker.text(toNative=nativePaths), |
|
234 self.pythonExecPicker.text(toNative=nativePaths), |
|
235 self.globalCheckBox.isChecked(), |
|
236 self.anacondaCheckBox.isChecked(), |
|
237 self.remoteCheckBox.isChecked(), |
|
238 self.execPathEdit.text(), |
|
239 ) |