|
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 manage the list of defined virtual |
|
8 environments. |
|
9 """ |
|
10 |
|
11 from PyQt5.QtCore import pyqtSlot, Qt |
|
12 from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QHeaderView |
|
13 |
|
14 from E5Gui.E5PathPicker import E5PathPickerModes |
|
15 |
|
16 from .Ui_VirtualenvManagerDialog import Ui_VirtualenvManagerDialog |
|
17 |
|
18 import Utilities |
|
19 |
|
20 |
|
21 class VirtualenvManagerDialog(QDialog, Ui_VirtualenvManagerDialog): |
|
22 """ |
|
23 Class implementing a dialog to manage the list of defined virtual |
|
24 environments. |
|
25 """ |
|
26 IsGlobalRole = Qt.ItemDataRole.UserRole + 1 |
|
27 IsCondaRole = Qt.ItemDataRole.UserRole + 2 |
|
28 IsRemoteRole = Qt.ItemDataRole.UserRole + 3 |
|
29 ExecPathRole = Qt.ItemDataRole.UserRole + 4 |
|
30 |
|
31 def __init__(self, manager, parent=None): |
|
32 """ |
|
33 Constructor |
|
34 |
|
35 @param manager reference to the virtual environment manager |
|
36 @type VirtualenvManager |
|
37 @param parent reference to the parent widget |
|
38 @type QWidget |
|
39 """ |
|
40 super().__init__(parent) |
|
41 self.setupUi(self) |
|
42 |
|
43 self.__manager = manager |
|
44 |
|
45 baseDir = self.__manager.getVirtualEnvironmentsBaseDir() |
|
46 if not baseDir: |
|
47 baseDir = Utilities.getHomeDir() |
|
48 |
|
49 self.envBaseDirectoryPicker.setMode(E5PathPickerModes.DirectoryMode) |
|
50 self.envBaseDirectoryPicker.setWindowTitle( |
|
51 self.tr("Virtualenv Base Directory")) |
|
52 self.envBaseDirectoryPicker.setText(baseDir) |
|
53 |
|
54 self.__populateVenvList() |
|
55 self.__updateButtons() |
|
56 |
|
57 self.venvList.header().setSortIndicator(0, Qt.SortOrder.AscendingOrder) |
|
58 |
|
59 def __updateButtons(self): |
|
60 """ |
|
61 Private method to update the enabled state of the various buttons. |
|
62 """ |
|
63 selectedItemsCount = len(self.venvList.selectedItems()) |
|
64 topLevelItemCount = self.venvList.topLevelItemCount() |
|
65 |
|
66 deletableSelectedItemCount = 0 |
|
67 for itm in self.venvList.selectedItems(): |
|
68 if ( |
|
69 itm.text(0) != "<default>" and |
|
70 bool(itm.text(1)) and |
|
71 not itm.data(0, VirtualenvManagerDialog.IsGlobalRole) and |
|
72 not itm.data(0, VirtualenvManagerDialog.IsRemoteRole) |
|
73 ): |
|
74 deletableSelectedItemCount += 1 |
|
75 |
|
76 deletableItemCount = 0 |
|
77 for index in range(topLevelItemCount): |
|
78 itm = self.venvList.topLevelItem(index) |
|
79 if ( |
|
80 itm.text(0) != "<default>" and |
|
81 bool(itm.text(1)) and |
|
82 not itm.data(0, VirtualenvManagerDialog.IsRemoteRole) |
|
83 ): |
|
84 deletableItemCount += 1 |
|
85 |
|
86 canBeRemoved = ( |
|
87 selectedItemsCount == 1 and |
|
88 self.venvList.selectedItems()[0].text(0) != "<default>" |
|
89 ) |
|
90 canAllBeRemoved = ( |
|
91 topLevelItemCount == 1 and |
|
92 self.venvList.topLevelItem(0).text(0) != "<default>" |
|
93 ) |
|
94 |
|
95 self.editButton.setEnabled(selectedItemsCount == 1) |
|
96 |
|
97 self.removeButton.setEnabled(selectedItemsCount > 1 or canBeRemoved) |
|
98 self.removeAllButton.setEnabled( |
|
99 topLevelItemCount > 1 or canAllBeRemoved) |
|
100 |
|
101 self.deleteButton.setEnabled(deletableSelectedItemCount) |
|
102 self.deleteAllButton.setEnabled(deletableItemCount) |
|
103 |
|
104 @pyqtSlot() |
|
105 def on_addButton_clicked(self): |
|
106 """ |
|
107 Private slot to add a new entry. |
|
108 """ |
|
109 from .VirtualenvAddEditDialog import VirtualenvAddEditDialog |
|
110 dlg = VirtualenvAddEditDialog( |
|
111 self.__manager, |
|
112 baseDir=self.envBaseDirectoryPicker.text() |
|
113 ) |
|
114 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
115 (venvName, venvDirectory, venvInterpreter, isGlobal, isConda, |
|
116 isRemote, execPath) = dlg.getData() |
|
117 |
|
118 self.__manager.addVirtualEnv( |
|
119 venvName, venvDirectory, venvInterpreter, isGlobal, isConda, |
|
120 isRemote, execPath) |
|
121 |
|
122 @pyqtSlot() |
|
123 def on_newButton_clicked(self): |
|
124 """ |
|
125 Private slot to create a new virtual environment. |
|
126 """ |
|
127 self.__manager.createVirtualEnv( |
|
128 baseDir=self.envBaseDirectoryPicker.text()) |
|
129 |
|
130 @pyqtSlot() |
|
131 def on_editButton_clicked(self): |
|
132 """ |
|
133 Private slot to edit the selected entry. |
|
134 """ |
|
135 selectedItem = self.venvList.selectedItems()[0] |
|
136 oldVenvName = selectedItem.text(0) |
|
137 |
|
138 from .VirtualenvAddEditDialog import VirtualenvAddEditDialog |
|
139 dlg = VirtualenvAddEditDialog( |
|
140 self.__manager, selectedItem.text(0), |
|
141 selectedItem.text(1), selectedItem.text(2), |
|
142 selectedItem.data(0, VirtualenvManagerDialog.IsGlobalRole), |
|
143 selectedItem.data(0, VirtualenvManagerDialog.IsCondaRole), |
|
144 selectedItem.data(0, VirtualenvManagerDialog.IsRemoteRole), |
|
145 selectedItem.data(0, VirtualenvManagerDialog.ExecPathRole), |
|
146 baseDir=self.envBaseDirectoryPicker.text() |
|
147 ) |
|
148 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
149 (venvName, venvDirectory, venvInterpreter, isGlobal, isConda, |
|
150 isRemote, execPath) = dlg.getData() |
|
151 if venvName != oldVenvName: |
|
152 self.__manager.renameVirtualEnv( |
|
153 oldVenvName, venvName, venvDirectory, venvInterpreter, |
|
154 isGlobal, isConda, isRemote, execPath) |
|
155 else: |
|
156 self.__manager.setVirtualEnv( |
|
157 venvName, venvDirectory, venvInterpreter, isGlobal, |
|
158 isConda, isRemote, execPath) |
|
159 |
|
160 @pyqtSlot() |
|
161 def on_removeButton_clicked(self): |
|
162 """ |
|
163 Private slot to remove all selected entries from the list but keep |
|
164 their directories. |
|
165 """ |
|
166 selectedVenvs = [] |
|
167 for itm in self.venvList.selectedItems(): |
|
168 selectedVenvs.append(itm.text(0)) |
|
169 |
|
170 if selectedVenvs: |
|
171 self.__manager.removeVirtualEnvs(selectedVenvs) |
|
172 |
|
173 @pyqtSlot() |
|
174 def on_removeAllButton_clicked(self): |
|
175 """ |
|
176 Private slot to remove all entries from the list but keep their |
|
177 directories. |
|
178 """ |
|
179 venvNames = [] |
|
180 for index in range(self.venvList.topLevelItemCount()): |
|
181 itm = self.venvList.topLevelItem(index) |
|
182 venvNames.append(itm.text(0)) |
|
183 |
|
184 if venvNames: |
|
185 self.__manager.removeVirtualEnvs(venvNames) |
|
186 |
|
187 @pyqtSlot() |
|
188 def on_deleteButton_clicked(self): |
|
189 """ |
|
190 Private slot to delete all selected entries from the list and disk. |
|
191 """ |
|
192 selectedVenvs = [] |
|
193 for itm in self.venvList.selectedItems(): |
|
194 selectedVenvs.append(itm.text(0)) |
|
195 |
|
196 if selectedVenvs: |
|
197 self.__manager.deleteVirtualEnvs(selectedVenvs) |
|
198 |
|
199 @pyqtSlot() |
|
200 def on_deleteAllButton_clicked(self): |
|
201 """ |
|
202 Private slot to delete all entries from the list and disk. |
|
203 """ |
|
204 venvNames = [] |
|
205 for index in range(self.venvList.topLevelItemCount()): |
|
206 itm = self.venvList.topLevelItem(index) |
|
207 venvNames.append(itm.text(0)) |
|
208 |
|
209 if venvNames: |
|
210 self.__manager.deleteVirtualEnvs(venvNames) |
|
211 |
|
212 @pyqtSlot() |
|
213 def on_venvList_itemSelectionChanged(self): |
|
214 """ |
|
215 Private slot handling a change of the selected items. |
|
216 """ |
|
217 self.__updateButtons() |
|
218 |
|
219 @pyqtSlot() |
|
220 def refresh(self): |
|
221 """ |
|
222 Public slot to refresh the list of shown items. |
|
223 """ |
|
224 # 1. remember selected entries |
|
225 selectedVenvs = [] |
|
226 for itm in self.venvList.selectedItems(): |
|
227 selectedVenvs.append(itm.text(0)) |
|
228 |
|
229 # 2. clear the list |
|
230 self.venvList.clear() |
|
231 |
|
232 # 3. re-populate the list |
|
233 self.__populateVenvList() |
|
234 |
|
235 # 4. re-establish selection |
|
236 for venvName in selectedVenvs: |
|
237 itms = self.venvList.findItems( |
|
238 venvName, Qt.MatchFlag.MatchExactly, 0) |
|
239 if itms: |
|
240 itms[0].setSelected(True) |
|
241 |
|
242 def __populateVenvList(self): |
|
243 """ |
|
244 Private method to populate the list of virtual environments. |
|
245 """ |
|
246 environments = self.__manager.getEnvironmentEntries() |
|
247 for venvName in environments: |
|
248 itm = QTreeWidgetItem(self.venvList, [ |
|
249 venvName, |
|
250 environments[venvName]["path"], |
|
251 environments[venvName]["interpreter"], |
|
252 ]) |
|
253 itm.setData(0, VirtualenvManagerDialog.IsGlobalRole, |
|
254 environments[venvName]["is_global"]) |
|
255 itm.setData(0, VirtualenvManagerDialog.IsCondaRole, |
|
256 environments[venvName]["is_conda"]) |
|
257 itm.setData(0, VirtualenvManagerDialog.IsRemoteRole, |
|
258 environments[venvName]["is_remote"]) |
|
259 itm.setData(0, VirtualenvManagerDialog.ExecPathRole, |
|
260 environments[venvName]["exec_path"]) |
|
261 |
|
262 # show remote environments with underlined font |
|
263 if environments[venvName]["is_remote"]: |
|
264 font = itm.font(0) |
|
265 font.setUnderline(True) |
|
266 for column in range(itm.columnCount()): |
|
267 itm.setFont(column, font) |
|
268 else: |
|
269 # local environments |
|
270 |
|
271 # show global environments with bold font |
|
272 if environments[venvName]["is_global"]: |
|
273 font = itm.font(0) |
|
274 font.setBold(True) |
|
275 for column in range(itm.columnCount()): |
|
276 itm.setFont(column, font) |
|
277 |
|
278 # show Anaconda environments with italic font |
|
279 if environments[venvName]["is_conda"]: |
|
280 font = itm.font(0) |
|
281 font.setItalic(True) |
|
282 for column in range(itm.columnCount()): |
|
283 itm.setFont(column, font) |
|
284 |
|
285 self.__resizeSections() |
|
286 |
|
287 def __resizeSections(self): |
|
288 """ |
|
289 Private method to resize the sections of the environment list to their |
|
290 contents. |
|
291 """ |
|
292 self.venvList.header().resizeSections( |
|
293 QHeaderView.ResizeMode.ResizeToContents) |
|
294 self.venvList.header().setStretchLastSection(True) |
|
295 |
|
296 def closeEvent(self, evt): |
|
297 """ |
|
298 Protected method to handle the close event. |
|
299 |
|
300 @param evt reference to the close event |
|
301 @type QCloseEvent |
|
302 """ |
|
303 baseDir = self.envBaseDirectoryPicker.text() |
|
304 self.__manager.setVirtualEnvironmentsBaseDir(baseDir) |
|
305 |
|
306 evt.accept() |