|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2013 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the .desktop wizard dialog. |
|
8 """ |
|
9 |
|
10 import os |
|
11 |
|
12 from PyQt5.QtCore import pyqtSlot |
|
13 from PyQt5.QtWidgets import QDialog, QDialogButtonBox |
|
14 |
|
15 from E5Gui.E5Application import e5App |
|
16 from E5Gui import E5MessageBox |
|
17 |
|
18 from .Ui_DotDesktopWizardDialog import Ui_DotDesktopWizardDialog |
|
19 |
|
20 import Utilities |
|
21 import UI.PixmapCache |
|
22 |
|
23 |
|
24 class DotDesktopWizardDialog(QDialog, Ui_DotDesktopWizardDialog): |
|
25 """ |
|
26 Class implementing the .desktop wizard dialog. |
|
27 """ |
|
28 def __init__(self, parent=None): |
|
29 """ |
|
30 Constructor |
|
31 |
|
32 @param parent reference to the parent widget (QWidget) |
|
33 """ |
|
34 super().__init__(parent) |
|
35 self.setupUi(self) |
|
36 |
|
37 self.buttonBox.button( |
|
38 QDialogButtonBox.StandardButton.Ok).setEnabled(False) |
|
39 |
|
40 self.__mainCategories = [ |
|
41 'AudioVideo', 'Audio', 'Video', 'Development', 'Education', |
|
42 'Game', 'Graphics', 'Network', 'Office', 'Science', 'Settings', |
|
43 'System', 'Utility', |
|
44 ] |
|
45 |
|
46 self.__subCategories = [ |
|
47 'Building', 'Debugger', 'IDE', 'GUIDesigner', 'Profiling', |
|
48 'RevisionControl', 'Translation', 'Calendar', 'ContactManagement', |
|
49 'Database', 'Dictionary', 'Chart', 'Email', 'Finance', 'FlowChart', |
|
50 'PDA', 'ProjectManagement', 'Presentation', 'Spreadsheet', |
|
51 'WordProcessor', '2DGraphics', 'VectorGraphics', 'RasterGraphics', |
|
52 '3DGraphics', 'Scanning', 'OCR', 'Photography', 'Publishing', |
|
53 'Viewer', 'TextTools', 'DesktopSettings', 'HardwareSettings', |
|
54 'Printing', 'PackageManager', 'Dialup', 'InstantMessaging', 'Chat', |
|
55 'IRCClient', 'Feed', 'FileTransfer', 'HamRadio', 'News', 'P2P', |
|
56 'RemoteAccess', 'Telephony', 'TelephonyTools', 'VideoConference', |
|
57 'WebBrowser', 'WebDevelopment', 'Midi', 'Mixer', 'Sequencer', |
|
58 'Tuner', 'TV', 'AudioVideoEditing', 'Player', 'Recorder', |
|
59 'DiscBurning', 'ActionGame', 'AdventureGame', 'ArcadeGame', |
|
60 'BoardGame', 'BlocksGame', 'CardGame', 'KidsGame', 'LogicGame', |
|
61 'RolePlaying', 'Shooter', 'Simulation', 'SportsGame', |
|
62 'StrategyGame', 'Art', 'Construction', 'Music', 'Languages', |
|
63 'ArtificialIntelligence', 'Astronomy', 'Biology', 'Chemistry', |
|
64 'ComputerScience', 'DataVisualization', 'Economy', 'Electricity', |
|
65 'Geography', 'Geology', 'Geoscience', 'History', 'Humanities', |
|
66 'ImageProcessing', 'Literature', 'Maps', 'Math', |
|
67 'NumericalAnalysis', 'MedicalSoftware', 'Physics', 'Robotics', |
|
68 'Spirituality', 'Sports', 'ParallelComputing', 'Amusement', |
|
69 'Archiving', 'Compression', 'Electronics', 'Emulator', |
|
70 'Engineering', 'FileTools', 'FileManager', 'TerminalEmulator', |
|
71 'Filesystem', 'Monitor', 'Security', 'Accessibility', 'Calculator', |
|
72 'Clock', 'TextEditor', 'Documentation', 'Adult', 'Core', 'KDE', |
|
73 'GNOME', 'XFCE', 'GTK', 'Qt', 'Motif', 'Java', 'ConsoleOnly', |
|
74 ] |
|
75 |
|
76 self.__showinEnvironments = [ |
|
77 'GNOME', 'KDE', 'LXDE', 'LXQt', 'MATE', 'Razor', 'ROX', 'TDE', |
|
78 'Unity', 'XFCE', 'EDE', 'Cinnamon', 'Pantheon', 'Old', |
|
79 ] |
|
80 |
|
81 self.typeComboBox.addItems([ |
|
82 self.tr("FreeDesktop Standard .desktop"), |
|
83 self.tr("KDE Plasma MetaData .desktop"), |
|
84 self.tr("Ubuntu Unity QuickList .desktop"), |
|
85 ]) |
|
86 |
|
87 self.kdeCategoryComboBox.addItems([ |
|
88 '', 'Application Launchers', 'Accessibility', 'Astronomy', |
|
89 'Date and Time', 'Development Tools', 'Education', 'Environment', |
|
90 'Examples', 'File System', 'Fun and Games', 'Graphics', |
|
91 'Language', 'Mapping', 'Multimedia', 'Online Services', |
|
92 'System Information', 'Utilities', 'Windows and Tasks', |
|
93 'Miscelaneous', |
|
94 ]) |
|
95 |
|
96 self.kdeApiComboBox.addItems([ |
|
97 'Python', 'Javascript', 'Ruby', 'C++', 'HTML5', 'QML' |
|
98 ]) |
|
99 |
|
100 self.kdeEncodingComboBox.addItems(sorted(Utilities.supportedCodecs)) |
|
101 self.kdeEncodingComboBox.setCurrentIndex( |
|
102 self.kdeEncodingComboBox.findText("utf-8")) |
|
103 |
|
104 projectOpen = e5App().getObject("Project").isOpen() |
|
105 self.projectButton.setEnabled(projectOpen) |
|
106 |
|
107 icon = UI.PixmapCache.getIcon("listSelection") |
|
108 self.categoriesButton.setIcon(icon) |
|
109 self.onlyShowButton.setIcon(icon) |
|
110 self.notShowButton.setIcon(icon) |
|
111 |
|
112 def getCode(self): |
|
113 """ |
|
114 Public method to get the source code. |
|
115 |
|
116 @return generated code (string) |
|
117 """ |
|
118 # step 1: standard desktop entries |
|
119 code = [ |
|
120 '[Desktop Entry]', |
|
121 'Type=' + self.typeEdit.text(), |
|
122 ] |
|
123 if self.versionEdit.text(): |
|
124 code.append('Version=' + self.versionEdit.text()) |
|
125 code.append('Name=' + self.nameEdit.text()) |
|
126 if self.genericNameEdit.text(): |
|
127 code.append('GenericName=' + self.genericNameEdit.text()) |
|
128 if self.commentEdit.text(): |
|
129 code.append('Comment=' + self.commentEdit.text()) |
|
130 if self.iconFileEdit.text(): |
|
131 code.append('Icon=' + self.iconFileEdit.text()) |
|
132 if self.onlyShowEdit.text(): |
|
133 code.append('OnlyShowIn=' + self.onlyShowEdit.text()) |
|
134 if self.notShowEdit.text(): |
|
135 code.append('NotShowIn=' + self.notShowEdit.text()) |
|
136 if self.tryExecEdit.text(): |
|
137 code.append('TryExec=' + self.tryExecEdit.text()) |
|
138 if self.execEdit.text(): |
|
139 code.append('Exec=' + self.execEdit.text()) |
|
140 if self.pathEdit.text(): |
|
141 code.append('Path=' + self.pathEdit.text()) |
|
142 if self.terminalCheckBox.isChecked(): |
|
143 code.append('Terminal=true') |
|
144 if self.actionsEdit.text(): |
|
145 code.append('Actions=' + self.actionsEdit.text()) |
|
146 if self.mimetypeEdit.text(): |
|
147 code.append('MimeType=' + self.mimetypeEdit.text()) |
|
148 if self.categoriesEdit.text(): |
|
149 code.append('Categories=' + self.categoriesEdit.text()) |
|
150 |
|
151 # step 2a: KDE Plasma entries |
|
152 if self.typeComboBox.currentIndex() == 1: |
|
153 if self.kdeEncodingComboBox.currentText(): |
|
154 code.append('Encoding=' + |
|
155 self.kdeEncodingComboBox.currentText()) |
|
156 if self.kdeServiceTypeEdit.text(): |
|
157 code.append('ServiceTypes=' + |
|
158 self.kdeServiceTypeEdit.text()) |
|
159 if self.kdeApiComboBox.currentText(): |
|
160 code.append('X-Plasma-API=' + |
|
161 self.kdeApiComboBox.currentText()) |
|
162 if self.kdeMainScriptEdit.text(): |
|
163 code.append('X-Plasma-MainScript=' + |
|
164 self.kdeMainScriptEdit.text()) |
|
165 if self.kdeAuthorEdit.text(): |
|
166 code.append('X-KDE-PluginInfo-Author=' + |
|
167 self.kdeAuthorEdit.text()) |
|
168 if self.kdeEmailEdit.text(): |
|
169 code.append('X-KDE-PluginInfo-Email=' + |
|
170 self.kdeEmailEdit.text()) |
|
171 if self.kdeNameEdit.text(): |
|
172 code.append('X-KDE-PluginInfo-Name=' + |
|
173 self.kdeNameEdit.text()) |
|
174 if self.kdeVersionEdit.text(): |
|
175 code.append('X-KDE-PluginInfo-Version=' + |
|
176 self.kdeVersionEdit.text()) |
|
177 if self.kdeWebsiteEdit.text(): |
|
178 code.append('X-KDE-PluginInfo-Website=' + |
|
179 self.kdeWebsiteEdit.text()) |
|
180 if self.kdeCategoryComboBox.currentText(): |
|
181 code.append('X-KDE-PluginInfo-Category=' + |
|
182 self.kdeCategoryComboBox.currentText()) |
|
183 if self.kdeDependsEdit.text(): |
|
184 code.append('X-KDE-PluginInfo-Depends=' + |
|
185 self.kdeDependsEdit.text()) |
|
186 if self.kdeLicensEdit.text(): |
|
187 code.append('X-KDE-PluginInfo-License=' + |
|
188 self.kdeLicensEdit.text()) |
|
189 if self.kdeEnabledDefaultCheckBox.isChecked(): |
|
190 code.append('X-KDE-PluginInfo-EnabledByDefault=true') |
|
191 |
|
192 # step 2b: Unity entries |
|
193 if ( |
|
194 self.typeComboBox.currentIndex() == 2 and |
|
195 self.unityShortcutsEdit.text() |
|
196 ): |
|
197 code.append('X-Ayatana-Desktop-Shortcuts=' + |
|
198 self.unityShortcutsEdit.text()) |
|
199 |
|
200 # step 3: action entries |
|
201 actions = [act for act in self.actionsEdit.text().split(";") if act] |
|
202 for act in actions: |
|
203 code.append('') |
|
204 code.append('[Desktop Action {0}]'.format(act)) |
|
205 code.append('Name={0}'.format(act)) |
|
206 code.append('Icon=<Icon Path>') |
|
207 code.append('Exec=<Executable command>') |
|
208 |
|
209 # step 4: add empty last line |
|
210 code.append('') |
|
211 |
|
212 return os.linesep.join(code) |
|
213 |
|
214 def __checkOK(self): |
|
215 """ |
|
216 Private slot to check, if the OK button should be enabled. |
|
217 """ |
|
218 enable = bool(self.nameEdit.text()) and bool(self.typeEdit.text()) |
|
219 if bool(self.onlyShowEdit.text()) and bool(self.notShowEdit.text()): |
|
220 enable = False |
|
221 self.buttonBox.button( |
|
222 QDialogButtonBox.StandardButton.Ok).setEnabled(enable) |
|
223 |
|
224 @pyqtSlot(int) |
|
225 def on_typeComboBox_currentIndexChanged(self, index): |
|
226 """ |
|
227 Private slot to handle a change of the .desktop type. |
|
228 |
|
229 @param index index of the selected entry (integer) |
|
230 """ |
|
231 self.dataTabWidget.setTabEnabled(1, index == 1) |
|
232 self.dataTabWidget.setTabEnabled(2, index == 2) |
|
233 |
|
234 @pyqtSlot() |
|
235 def on_projectButton_clicked(self): |
|
236 """ |
|
237 Private slot to populate some fields with data retrieved from the |
|
238 current project. |
|
239 """ |
|
240 project = e5App().getObject("Project") |
|
241 |
|
242 self.nameEdit.setText(project.getProjectName()) |
|
243 self.genericNameEdit.setText(project.getProjectName()) |
|
244 self.kdeNameEdit.setText(project.getProjectName()) |
|
245 try: |
|
246 self.kdeVersionEdit.setText(project.getProjectVersion()) |
|
247 self.kdeAuthorEdit.setText(project.getProjectAuthor()) |
|
248 self.kdeEmailEdit.setText(project.getProjectAuthorEmail()) |
|
249 except AttributeError: |
|
250 self.kdeVersionEdit.setText(project.pdata["VERSION"][0]) |
|
251 self.kdeAuthorEdit.setText(project.pdata["AUTHOR"][0]) |
|
252 self.kdeEmailEdit.setText(project.pdata["EMAIL"][0]) |
|
253 mainscript = project.getMainScript(True) |
|
254 if mainscript: |
|
255 self.kdeMainScriptEdit.setText(mainscript) |
|
256 self.execEdit.setText(mainscript) |
|
257 self.tryExecEdit.setText(mainscript) |
|
258 |
|
259 # prevent overwriting of entries by disabling the button |
|
260 self.projectButton.setEnabled(False) |
|
261 |
|
262 @pyqtSlot() |
|
263 def on_categoriesButton_clicked(self): |
|
264 """ |
|
265 Private slot to select the categories. |
|
266 """ |
|
267 from .DotDesktopListSelectionDialog import ( |
|
268 DotDesktopListSelectionDialog |
|
269 ) |
|
270 dlg = DotDesktopListSelectionDialog( |
|
271 self.__mainCategories, |
|
272 self.categoriesEdit.text(), ";", |
|
273 subEntries=self.__subCategories, |
|
274 allowMultiMain=False) |
|
275 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
276 categories = dlg.getData(";", True) |
|
277 self.categoriesEdit.setText(categories) |
|
278 |
|
279 @pyqtSlot(str) |
|
280 def on_onlyShowEdit_textChanged(self, txt): |
|
281 """ |
|
282 Private slot to check the contents of the onlyShowEdit field. |
|
283 |
|
284 @param txt text of the entry field (string) |
|
285 """ |
|
286 self.__checkOK() |
|
287 if bool(self.onlyShowEdit.text()) and bool(self.notShowEdit.text()): |
|
288 E5MessageBox.critical( |
|
289 self, |
|
290 self.tr(".desktop Wizard"), |
|
291 self.tr("""Only one of 'Only Show In' or """ |
|
292 """ 'Not Show In' allowed.""")) |
|
293 |
|
294 @pyqtSlot() |
|
295 def on_onlyShowButton_clicked(self): |
|
296 """ |
|
297 Private slot to select the OnlyShowIn environments. |
|
298 """ |
|
299 from .DotDesktopListSelectionDialog import ( |
|
300 DotDesktopListSelectionDialog |
|
301 ) |
|
302 dlg = DotDesktopListSelectionDialog( |
|
303 self.__showinEnvironments, |
|
304 self.onlyShowEdit.text(), ";") |
|
305 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
306 environments = dlg.getData(";", True) |
|
307 self.onlyShowEdit.setText(environments) |
|
308 |
|
309 @pyqtSlot(str) |
|
310 def on_notShowEdit_textChanged(self, txt): |
|
311 """ |
|
312 Private slot to check the contents of the notShowEdit field. |
|
313 |
|
314 @param txt text of the entry field (string) |
|
315 """ |
|
316 self.__checkOK() |
|
317 if bool(self.onlyShowEdit.text()) and bool(self.notShowEdit.text()): |
|
318 E5MessageBox.critical( |
|
319 self, |
|
320 self.tr(".desktop Wizard"), |
|
321 self.tr("""Only one of 'Only Show In' or """ |
|
322 """ 'Not Show In' allowed.""")) |
|
323 |
|
324 @pyqtSlot() |
|
325 def on_notShowButton_clicked(self): |
|
326 """ |
|
327 Private slot to select the NotShowIn environments. |
|
328 """ |
|
329 from .DotDesktopListSelectionDialog import ( |
|
330 DotDesktopListSelectionDialog |
|
331 ) |
|
332 dlg = DotDesktopListSelectionDialog( |
|
333 self.__showinEnvironments, |
|
334 self.notShowEdit.text(), ";") |
|
335 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
336 environments = dlg.getData(";", True) |
|
337 self.notShowEdit.setText(environments) |
|
338 |
|
339 @pyqtSlot(str) |
|
340 def on_typeEdit_textChanged(self, txt): |
|
341 """ |
|
342 Private slot to check, if the typeEdit field is empty. |
|
343 |
|
344 @param txt text of the entry field (string) |
|
345 """ |
|
346 self.__checkOK() |
|
347 |
|
348 @pyqtSlot(str) |
|
349 def on_nameEdit_textChanged(self, txt): |
|
350 """ |
|
351 Private slot to check, if the nameEdit field is empty. |
|
352 |
|
353 @param txt text of the entry field (string) |
|
354 """ |
|
355 self.__checkOK() |