|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a configuration dialog for the tools menu. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 |
|
12 import copy |
|
13 |
|
14 from PyQt5.QtCore import Qt, pyqtSlot |
|
15 from PyQt5.QtWidgets import QDialog |
|
16 |
|
17 from E5Gui import E5MessageBox |
|
18 from E5Gui.E5PathPicker import E5PathPickerModes |
|
19 |
|
20 from .Ui_ToolConfigurationDialog import Ui_ToolConfigurationDialog |
|
21 |
|
22 import Utilities |
|
23 |
|
24 |
|
25 class ToolConfigurationDialog(QDialog, Ui_ToolConfigurationDialog): |
|
26 """ |
|
27 Class implementing a configuration dialog for the tools menu. |
|
28 """ |
|
29 def __init__(self, toollist, parent=None): |
|
30 """ |
|
31 Constructor |
|
32 |
|
33 @param toollist list of configured tools |
|
34 @param parent parent widget (QWidget) |
|
35 """ |
|
36 super(ToolConfigurationDialog, self).__init__(parent) |
|
37 self.setupUi(self) |
|
38 |
|
39 self.iconPicker.setMode(E5PathPickerModes.OpenFileMode) |
|
40 self.iconPicker.setFilters(self.tr("Icon files (*.png)")) |
|
41 self.executablePicker.setMode(E5PathPickerModes.OpenFileMode) |
|
42 |
|
43 self.redirectionModes = [ |
|
44 ("no", self.tr("no redirection")), |
|
45 ("show", self.tr("show output")), |
|
46 ("insert", self.tr("insert into current editor")), |
|
47 ("replaceSelection", |
|
48 self.tr("replace selection of current editor")), |
|
49 ] |
|
50 |
|
51 self.toollist = copy.deepcopy(toollist) |
|
52 for tool in toollist: |
|
53 self.toolsList.addItem(tool['menutext']) |
|
54 |
|
55 for mode in self.redirectionModes: |
|
56 self.redirectCombo.addItem(mode[1]) |
|
57 |
|
58 if len(toollist): |
|
59 self.toolsList.setCurrentRow(0) |
|
60 self.on_toolsList_currentRowChanged(0) |
|
61 |
|
62 t = self.argumentsEdit.whatsThis() |
|
63 if t: |
|
64 t += Utilities.getPercentReplacementHelp() |
|
65 self.argumentsEdit.setWhatsThis(t) |
|
66 |
|
67 def __findModeIndex(self, shortName): |
|
68 """ |
|
69 Private method to find the mode index by its short name. |
|
70 |
|
71 @param shortName short name of the mode (string) |
|
72 @return index of the mode (integer) |
|
73 """ |
|
74 ind = 0 |
|
75 for mode in self.redirectionModes: |
|
76 if mode[0] == shortName: |
|
77 return ind |
|
78 ind += 1 |
|
79 return 1 # default is "show output" |
|
80 |
|
81 @pyqtSlot() |
|
82 def on_newButton_clicked(self): |
|
83 """ |
|
84 Private slot to clear all entry fields. |
|
85 """ |
|
86 self.executablePicker.clear() |
|
87 self.menuEdit.clear() |
|
88 self.iconPicker.clear() |
|
89 self.argumentsEdit.clear() |
|
90 self.redirectCombo.setCurrentIndex(1) |
|
91 |
|
92 @pyqtSlot() |
|
93 def on_addButton_clicked(self): |
|
94 """ |
|
95 Private slot to add a new entry. |
|
96 """ |
|
97 menutext = self.menuEdit.text() |
|
98 icon = self.iconPicker.text() |
|
99 executable = self.executablePicker.text() |
|
100 arguments = self.argumentsEdit.text() |
|
101 redirect = self.redirectionModes[self.redirectCombo.currentIndex()][0] |
|
102 |
|
103 if not executable: |
|
104 E5MessageBox.critical( |
|
105 self, |
|
106 self.tr("Add tool entry"), |
|
107 self.tr( |
|
108 "You have to set an executable to add to the" |
|
109 " Tools-Menu first.")) |
|
110 return |
|
111 |
|
112 if not menutext: |
|
113 E5MessageBox.critical( |
|
114 self, |
|
115 self.tr("Add tool entry"), |
|
116 self.tr( |
|
117 "You have to insert a menuentry text to add the" |
|
118 " selected program to the Tools-Menu first.")) |
|
119 return |
|
120 |
|
121 if not Utilities.isinpath(executable): |
|
122 E5MessageBox.critical( |
|
123 self, |
|
124 self.tr("Add tool entry"), |
|
125 self.tr( |
|
126 "The selected file could not be found or" |
|
127 " is not an executable." |
|
128 " Please choose an executable filename.")) |
|
129 return |
|
130 |
|
131 if len(self.toolsList.findItems( |
|
132 menutext, Qt.MatchFlags(Qt.MatchExactly))): |
|
133 E5MessageBox.critical( |
|
134 self, |
|
135 self.tr("Add tool entry"), |
|
136 self.tr("An entry for the menu text {0} already exists.") |
|
137 .format(menutext)) |
|
138 return |
|
139 |
|
140 self.toolsList.addItem(menutext) |
|
141 tool = { |
|
142 'menutext': menutext, |
|
143 'icon': icon, |
|
144 'executable': executable, |
|
145 'arguments': arguments, |
|
146 'redirect': redirect, |
|
147 } |
|
148 self.toollist.append(tool) |
|
149 |
|
150 @pyqtSlot() |
|
151 def on_changeButton_clicked(self): |
|
152 """ |
|
153 Private slot to change an entry. |
|
154 """ |
|
155 row = self.toolsList.currentRow() |
|
156 if row < 0: |
|
157 return |
|
158 |
|
159 menutext = self.menuEdit.text() |
|
160 icon = self.iconPicker.text() |
|
161 executable = self.executablePicker.text() |
|
162 arguments = self.argumentsEdit.text() |
|
163 redirect = self.redirectionModes[self.redirectCombo.currentIndex()][0] |
|
164 |
|
165 if not executable: |
|
166 E5MessageBox.critical( |
|
167 self, |
|
168 self.tr("Change tool entry"), |
|
169 self.tr( |
|
170 "You have to set an executable to change the" |
|
171 " Tools-Menu entry.")) |
|
172 return |
|
173 |
|
174 if not menutext: |
|
175 E5MessageBox.critical( |
|
176 self, |
|
177 self.tr("Change tool entry"), |
|
178 self.tr( |
|
179 "You have to insert a menuentry text to change the" |
|
180 " selected Tools-Menu entry.")) |
|
181 return |
|
182 |
|
183 if not Utilities.isinpath(executable): |
|
184 E5MessageBox.critical( |
|
185 self, |
|
186 self.tr("Change tool entry"), |
|
187 self.tr( |
|
188 "The selected file could not be found or" |
|
189 " is not an executable." |
|
190 " Please choose an existing executable filename.")) |
|
191 return |
|
192 |
|
193 self.toollist[row] = { |
|
194 'menutext': menutext, |
|
195 'icon': icon, |
|
196 'executable': executable, |
|
197 'arguments': arguments, |
|
198 'redirect': redirect, |
|
199 } |
|
200 self.toolsList.currentItem().setText(menutext) |
|
201 self.changeButton.setEnabled(False) |
|
202 |
|
203 @pyqtSlot() |
|
204 def on_deleteButton_clicked(self): |
|
205 """ |
|
206 Private slot to delete the selected entry. |
|
207 """ |
|
208 row = self.toolsList.currentRow() |
|
209 if row < 0: |
|
210 return |
|
211 |
|
212 del self.toollist[row] |
|
213 itm = self.toolsList.takeItem(row) |
|
214 del itm |
|
215 if row >= len(self.toollist): |
|
216 row -= 1 |
|
217 self.toolsList.setCurrentRow(row) |
|
218 self.on_toolsList_currentRowChanged(row) |
|
219 |
|
220 @pyqtSlot() |
|
221 def on_downButton_clicked(self): |
|
222 """ |
|
223 Private slot to move an entry down in the list. |
|
224 """ |
|
225 curr = self.toolsList.currentRow() |
|
226 self.__swap(curr, curr + 1) |
|
227 self.toolsList.clear() |
|
228 for tool in self.toollist: |
|
229 self.toolsList.addItem(tool['menutext']) |
|
230 self.toolsList.setCurrentRow(curr + 1) |
|
231 if curr + 1 == len(self.toollist): |
|
232 self.downButton.setEnabled(False) |
|
233 self.upButton.setEnabled(True) |
|
234 |
|
235 @pyqtSlot() |
|
236 def on_upButton_clicked(self): |
|
237 """ |
|
238 Private slot to move an entry up in the list. |
|
239 """ |
|
240 curr = self.toolsList.currentRow() |
|
241 self.__swap(curr - 1, curr) |
|
242 self.toolsList.clear() |
|
243 for tool in self.toollist: |
|
244 self.toolsList.addItem(tool['menutext']) |
|
245 self.toolsList.setCurrentRow(curr - 1) |
|
246 if curr - 1 == 0: |
|
247 self.upButton.setEnabled(False) |
|
248 self.downButton.setEnabled(True) |
|
249 |
|
250 @pyqtSlot() |
|
251 def on_separatorButton_clicked(self): |
|
252 """ |
|
253 Private slot to add a menu separator. |
|
254 """ |
|
255 self.toolsList.addItem('--') |
|
256 tool = { |
|
257 'menutext': '--', |
|
258 'icon': '', |
|
259 'executable': '', |
|
260 'arguments': '', |
|
261 'redirect': 'no', |
|
262 } |
|
263 self.toollist.append(tool) |
|
264 |
|
265 @pyqtSlot(str) |
|
266 def on_executablePicker_pathSelected(self, path): |
|
267 """ |
|
268 Private slot to check the executable after it has been selected. |
|
269 |
|
270 @param path path of the executable |
|
271 @type str |
|
272 """ |
|
273 if path: |
|
274 if not Utilities.isinpath(path): |
|
275 E5MessageBox.critical( |
|
276 self, |
|
277 self.tr("Select executable"), |
|
278 self.tr( |
|
279 "The selected file is not an executable." |
|
280 " Please choose an executable filename.")) |
|
281 |
|
282 def on_toolsList_currentRowChanged(self, row): |
|
283 """ |
|
284 Private slot to set the lineedits depending on the selected entry. |
|
285 |
|
286 @param row the row of the selected entry (integer) |
|
287 """ |
|
288 if row >= 0 and row < len(self.toollist): |
|
289 if self.toollist[row]['menutext'] == '--': |
|
290 self.executablePicker.clear() |
|
291 self.menuEdit.clear() |
|
292 self.iconPicker.clear() |
|
293 self.argumentsEdit.clear() |
|
294 self.redirectCombo.setCurrentIndex(0) |
|
295 else: |
|
296 tool = self.toollist[row] |
|
297 self.menuEdit.setText(tool['menutext']) |
|
298 self.iconPicker.setText(tool['icon']) |
|
299 self.executablePicker.setText(tool['executable']) |
|
300 self.argumentsEdit.setText(tool['arguments']) |
|
301 self.redirectCombo.setCurrentIndex( |
|
302 self.__findModeIndex(tool['redirect'])) |
|
303 |
|
304 self.changeButton.setEnabled(False) |
|
305 self.deleteButton.setEnabled(True) |
|
306 |
|
307 if row != 0: |
|
308 self.upButton.setEnabled(True) |
|
309 else: |
|
310 self.upButton.setEnabled(False) |
|
311 |
|
312 if row + 1 != len(self.toollist): |
|
313 self.downButton.setEnabled(True) |
|
314 else: |
|
315 self.downButton.setEnabled(False) |
|
316 else: |
|
317 self.executablePicker.clear() |
|
318 self.menuEdit.clear() |
|
319 self.iconPicker.clear() |
|
320 self.argumentsEdit.clear() |
|
321 self.downButton.setEnabled(False) |
|
322 self.upButton.setEnabled(False) |
|
323 self.deleteButton.setEnabled(False) |
|
324 self.changeButton.setEnabled(False) |
|
325 |
|
326 def __toolEntryChanged(self): |
|
327 """ |
|
328 Private slot to perform actions when a tool entry was changed. |
|
329 """ |
|
330 row = self.toolsList.currentRow() |
|
331 if row >= 0 and \ |
|
332 row < len(self.toollist) and \ |
|
333 self.toollist[row]['menutext'] != '--': |
|
334 self.changeButton.setEnabled(True) |
|
335 |
|
336 def on_menuEdit_textChanged(self, text): |
|
337 """ |
|
338 Private slot called, when the menu text was changed. |
|
339 |
|
340 @param text the new text (string) (ignored) |
|
341 """ |
|
342 self.__toolEntryChanged() |
|
343 |
|
344 def on_iconPicker_textChanged(self, text): |
|
345 """ |
|
346 Private slot called, when the icon path was changed. |
|
347 |
|
348 @param text the new text (string) (ignored) |
|
349 """ |
|
350 self.__toolEntryChanged() |
|
351 |
|
352 def on_executablePicker_textChanged(self, text): |
|
353 """ |
|
354 Private slot called, when the executable was changed. |
|
355 |
|
356 @param text the new text (string) (ignored) |
|
357 """ |
|
358 self.__toolEntryChanged() |
|
359 |
|
360 def on_argumentsEdit_textChanged(self, text): |
|
361 """ |
|
362 Private slot called, when the arguments string was changed. |
|
363 |
|
364 @param text the new text (string) (ignored) |
|
365 """ |
|
366 self.__toolEntryChanged() |
|
367 |
|
368 @pyqtSlot(int) |
|
369 def on_redirectCombo_currentIndexChanged(self, index): |
|
370 """ |
|
371 Private slot called, when the redirection mode was changed. |
|
372 |
|
373 @param index the selected mode index (integer) (ignored) |
|
374 """ |
|
375 self.__toolEntryChanged() |
|
376 |
|
377 def getToollist(self): |
|
378 """ |
|
379 Public method to retrieve the tools list. |
|
380 |
|
381 @return a list of tuples containing the menu text, the executable, |
|
382 the executables arguments and a redirection flag |
|
383 """ |
|
384 return self.toollist[:] |
|
385 |
|
386 def __swap(self, itm1, itm2): |
|
387 """ |
|
388 Private method used two swap two list entries given by their index. |
|
389 |
|
390 @param itm1 index of first entry (int) |
|
391 @param itm2 index of second entry (int) |
|
392 """ |
|
393 tmp = self.toollist[itm1] |
|
394 self.toollist[itm1] = self.toollist[itm2] |
|
395 self.toollist[itm2] = tmp |