eric6/Preferences/ProgramsDialog.py

changeset 6942
2602857055c5
parent 6782
390a45748883
child 7192
a22eee00b052
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2006 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the Programs page.
8 """
9
10 from __future__ import unicode_literals
11 try:
12 str = unicode
13 except NameError:
14 pass
15
16 import os
17 import re
18 import sys
19
20 from PyQt5.QtCore import pyqtSlot, Qt, QProcess
21 from PyQt5.QtGui import QCursor
22 from PyQt5.QtWidgets import QApplication, QTreeWidgetItem, QHeaderView, \
23 QDialog, QDialogButtonBox
24
25 from E5Gui.E5Application import e5App
26
27 from .Ui_ProgramsDialog import Ui_ProgramsDialog
28
29 import Preferences
30 import Utilities
31
32
33 class ProgramsDialog(QDialog, Ui_ProgramsDialog):
34 """
35 Class implementing the Programs page.
36 """
37 def __init__(self, parent=None):
38 """
39 Constructor
40
41 @param parent The parent widget of this dialog. (QWidget)
42 """
43 super(ProgramsDialog, self).__init__(parent)
44 self.setupUi(self)
45 self.setObjectName("ProgramsDialog")
46 self.setWindowFlags(Qt.Window)
47
48 self.__hasSearched = False
49
50 self.programsList.headerItem().setText(
51 self.programsList.columnCount(), "")
52
53 self.searchButton = self.buttonBox.addButton(
54 self.tr("Search"), QDialogButtonBox.ActionRole)
55 self.searchButton.setToolTip(
56 self.tr("Press to search for programs"))
57
58 def show(self):
59 """
60 Public slot to show the dialog.
61 """
62 QDialog.show(self)
63 if not self.__hasSearched:
64 self.on_programsSearchButton_clicked()
65
66 def on_buttonBox_clicked(self, button):
67 """
68 Private slot called by a button of the button box clicked.
69
70 @param button button that was clicked (QAbstractButton)
71 """
72 if button == self.searchButton:
73 self.on_programsSearchButton_clicked()
74
75 @pyqtSlot()
76 def on_programsSearchButton_clicked(self):
77 """
78 Private slot to search for all supported/required programs.
79 """
80 QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
81 QApplication.processEvents()
82
83 self.programsList.clear()
84 header = self.programsList.header()
85 header.setSortIndicator(0, Qt.AscendingOrder)
86 header.setSortIndicatorShown(False)
87
88 # 1. do the Qt4/Qt5 programs
89 # 1a. Translation Converter
90 exe = Utilities.isWindowsPlatform() and \
91 "{0}.exe".format(Utilities.generateQtToolName("lrelease")) or \
92 Utilities.generateQtToolName("lrelease")
93 exe = os.path.join(Utilities.getQtBinariesPath(), exe)
94 version = self.__createProgramEntry(
95 self.tr("Translation Converter (Qt)"), exe, '-version',
96 'lrelease', -1)
97 # 1b. Qt Designer
98 if Utilities.isWindowsPlatform():
99 exe = os.path.join(
100 Utilities.getQtBinariesPath(),
101 "{0}.exe".format(Utilities.generateQtToolName("designer")))
102 elif Utilities.isMacPlatform():
103 exe = Utilities.getQtMacBundle("designer")
104 else:
105 exe = os.path.join(
106 Utilities.getQtBinariesPath(),
107 Utilities.generateQtToolName("designer"))
108 self.__createProgramEntry(
109 self.tr("Qt Designer"), exe, version=version)
110 # 1c. Qt Linguist
111 if Utilities.isWindowsPlatform():
112 exe = os.path.join(
113 Utilities.getQtBinariesPath(),
114 "{0}.exe".format(Utilities.generateQtToolName("linguist")))
115 elif Utilities.isMacPlatform():
116 exe = Utilities.getQtMacBundle("linguist")
117 else:
118 exe = os.path.join(
119 Utilities.getQtBinariesPath(),
120 Utilities.generateQtToolName("linguist"))
121 self.__createProgramEntry(
122 self.tr("Qt Linguist"), exe, version=version)
123 # 1d. Qt Assistant
124 if Utilities.isWindowsPlatform():
125 exe = os.path.join(
126 Utilities.getQtBinariesPath(),
127 "{0}.exe".format(Utilities.generateQtToolName("assistant")))
128 elif Utilities.isMacPlatform():
129 exe = Utilities.getQtMacBundle("assistant")
130 else:
131 exe = os.path.join(
132 Utilities.getQtBinariesPath(),
133 Utilities.generateQtToolName("assistant"))
134 self.__createProgramEntry(
135 self.tr("Qt Assistant"), exe, version=version)
136
137 # 2. do the PyQt programs
138 # 2.1 do the PyQt4 programs
139 # 2.1a. Translation Extractor PyQt4
140 self.__createProgramEntry(
141 self.tr("Translation Extractor (Python, PyQt4)"),
142 Utilities.generatePyQtToolPath("pylupdate4"),
143 '-version', 'pylupdate', -1)
144 # 2.1b. Forms Compiler PyQt4
145 self.__createProgramEntry(
146 self.tr("Forms Compiler (Python, PyQt4)"),
147 Utilities.generatePyQtToolPath("pyuic4", ["py3uic4", "py2uic4"]),
148 '--version', 'Python User', 4)
149 # 2.1c. Resource Compiler PyQt4
150 self.__createProgramEntry(
151 self.tr("Resource Compiler (Python, PyQt4)"),
152 Utilities.generatePyQtToolPath("pyrcc4"),
153 '-version', 'Resource Compiler', -1)
154
155 # 2.2 do the PyQt5 programs
156 # 2.2a. Translation Extractor PyQt5
157 self.__createProgramEntry(
158 self.tr("Translation Extractor (Python, PyQt5)"),
159 Utilities.generatePyQtToolPath("pylupdate5"),
160 '-version', 'pylupdate', -1)
161 # 2.2b. Forms Compiler PyQt5
162 self.__createProgramEntry(
163 self.tr("Forms Compiler (Python, PyQt5)"),
164 Utilities.generatePyQtToolPath("pyuic5", ["py3uic5", "py2uic5"]),
165 '--version', 'Python User', 4)
166 # 2.2c. Resource Compiler PyQt5
167 self.__createProgramEntry(
168 self.tr("Resource Compiler (Python, PyQt5)"),
169 Utilities.generatePyQtToolPath("pyrcc5"),
170 '-version', '', -1, versionRe='Resource Compiler|pyrcc5')
171
172 # 3.1 do the PySide programs
173 # 3.1a. Translation Extractor PySide
174 self.__createProgramEntry(
175 self.tr("Translation Extractor (Python, PySide)"),
176 Utilities.generatePySideToolPath("pyside-lupdate", "1"),
177 '-version', '', -1, versionRe='lupdate')
178 # 3.1b. Forms Compiler PySide
179 self.__createProgramEntry(
180 self.tr("Forms Compiler (Python, PySide)"),
181 Utilities.generatePySideToolPath("pyside-uic", "1"),
182 '--version', 'PySide User', 5, versionCleanup=(0, -1))
183 # 3.1c Resource Compiler PySide
184 self.__createProgramEntry(
185 self.tr("Resource Compiler (Python, PySide)"),
186 Utilities.generatePySideToolPath("pyside-rcc", "1"),
187 '-version', 'Resource Compiler', -1)
188
189 # 3.2 do the PySide2 programs
190 # 3.2a. Translation Extractor PySide2
191 self.__createProgramEntry(
192 self.tr("Translation Extractor (Python, PySide2)"),
193 Utilities.generatePySideToolPath("pyside2-lupdate", "2"),
194 '-version', '', -1, versionRe='lupdate')
195 # 3.2b. Forms Compiler PySide2
196 self.__createProgramEntry(
197 self.tr("Forms Compiler (Python, PySide2)"),
198 Utilities.generatePySideToolPath("pyside2-uic", "2"),
199 '--version', 'PySide2 User', -1, versionCleanup=(0, -1))
200 # 3.2c Resource Compiler PySide2
201 self.__createProgramEntry(
202 self.tr("Resource Compiler (Python, PySide2)"),
203 Utilities.generatePySideToolPath("pyside2-rcc", "2"),
204 '-version', 'Resource Compiler', -1)
205
206 # 4. do the Ruby programs
207 # 4a. Forms Compiler for Qt4
208 self.__createProgramEntry(
209 self.tr("Forms Compiler (Ruby, Qt4)"),
210 Utilities.isWindowsPlatform() and "rbuic4.exe" or "rbuic4",
211 '-version', 'Qt', -1)
212 # 4b. Resource Compiler for Qt4
213 self.__createProgramEntry(
214 self.tr("Resource Compiler (Ruby, Qt4)"),
215 Utilities.isWindowsPlatform() and "rbrcc.exe" or "rbrcc",
216 '-version', 'Ruby Resource Compiler', -1)
217
218 # 5. do the Conda program(s)
219 exe = Preferences.getConda("CondaExecutable")
220 if not exe:
221 exe = "conda"
222 if Utilities.isWindowsPlatform():
223 exe += ".exe"
224 self.__createProgramEntry(
225 self.tr("conda Manager"), exe, '--version', 'conda', -1)
226
227 # 6. do the pip program(s)
228 virtualenvManager = e5App().getObject("VirtualEnvManager")
229 for venvName in virtualenvManager.getVirtualenvNames():
230 interpreter = virtualenvManager.getVirtualenvInterpreter(venvName)
231 self.__createProgramEntry(
232 self.tr("PyPI Package Management"), interpreter, '--version',
233 'pip', 1, exeModule=["-m", "pip"])
234
235 # 7. do the CORBA and Protobuf programs
236 # 7a. omniORB
237 exe = Preferences.getCorba("omniidl")
238 if not exe:
239 exe = "omniidl"
240 if Utilities.isWindowsPlatform():
241 exe += ".exe"
242 self.__createProgramEntry(
243 self.tr("CORBA IDL Compiler"), exe, '-V', 'omniidl', -1)
244 # 7b. protobuf
245 exe = Preferences.getProtobuf("protoc")
246 if not exe:
247 exe = "protoc"
248 if Utilities.isWindowsPlatform():
249 exe += ".exe"
250 self.__createProgramEntry(
251 self.tr("Protobuf Compiler"), exe, '--version', 'libprotoc', -1)
252 # 7c. grpc
253 exe = Preferences.getProtobuf("grpcPython")
254 if not exe:
255 exe = sys.executable
256 self.__createProgramEntry(
257 self.tr("gRPC Compiler"), exe, '--version', 'libprotoc', -1,
258 exeModule=['-m', 'grpc_tools.protoc'])
259
260 # 8. do the spell checking entry
261 try:
262 import enchant
263 try:
264 text = os.path.dirname(enchant.__file__)
265 except AttributeError:
266 text = "enchant"
267 try:
268 version = enchant.__version__
269 except AttributeError:
270 version = self.tr("(unknown)")
271 except (ImportError, AttributeError, OSError):
272 text = "enchant"
273 version = ""
274 self.__createEntry(
275 self.tr("Spell Checker - PyEnchant"), text, version)
276
277 # 9. do the pygments entry
278 try:
279 import pygments
280 try:
281 text = os.path.dirname(pygments.__file__)
282 except AttributeError:
283 text = "pygments"
284 try:
285 version = pygments.__version__
286 except AttributeError:
287 version = self.tr("(unknown)")
288 except (ImportError, AttributeError, OSError):
289 text = "pygments"
290 version = ""
291 self.__createEntry(
292 self.tr("Source Highlighter - Pygments"), text, version)
293
294 # 10. do the plugin related programs
295 pm = e5App().getObject("PluginManager")
296 for info in pm.getPluginExeDisplayData():
297 if info["programEntry"]:
298 if "exeModule" not in info:
299 info["exeModule"] = None
300 if "versionRe" not in info:
301 info["versionRe"] = None
302 self.__createProgramEntry(
303 info["header"],
304 info["exe"],
305 versionCommand=info["versionCommand"],
306 versionStartsWith=info["versionStartsWith"],
307 versionPosition=info["versionPosition"],
308 version=info["version"],
309 versionCleanup=info["versionCleanup"],
310 versionRe=info["versionRe"],
311 exeModule=info["exeModule"],
312 )
313 else:
314 self.__createEntry(
315 info["header"],
316 info["text"],
317 info["version"]
318 )
319
320 self.programsList.sortByColumn(0, Qt.AscendingOrder)
321 QApplication.restoreOverrideCursor()
322
323 self.__hasSearched = True
324
325 def __createProgramEntry(self, description, exe,
326 versionCommand="", versionStartsWith="",
327 versionPosition=0, version="",
328 versionCleanup=None, versionRe=None,
329 exeModule=None):
330 """
331 Private method to generate a program entry.
332
333 @param description descriptive text (string)
334 @param exe name of the executable program (string)
335 @param versionCommand command line switch to get the version info
336 (str). If this is empty, the given version will be shown.
337 @param versionStartsWith start of line identifying version info
338 (string)
339 @param versionPosition index of part containing the version info
340 (integer)
341 @keyparam version version string to show (string)
342 @keyparam versionCleanup tuple of two integers giving string positions
343 start and stop for the version string (tuple of integers)
344 @keyparam versionRe regexp to determine the line identifying version
345 info (string). Takes precedence over versionStartsWith.
346 @keyparam exeModule list of command line parameters to execute a module
347 with the program given in exe (e.g. to execute a Python module)
348 (list of str)
349 @return version string of detected or given version (string)
350 """
351 itmList = self.programsList.findItems(
352 description, Qt.MatchCaseSensitive)
353 if itmList:
354 itm = itmList[0]
355 else:
356 itm = QTreeWidgetItem(self.programsList, [description])
357 font = itm.font(0)
358 font.setBold(True)
359 itm.setFont(0, font)
360 rememberedExe = exe
361 if not exe:
362 itm.setText(1, self.tr("(not configured)"))
363 else:
364 if os.path.isabs(exe):
365 if not Utilities.isExecutable(exe):
366 exe = ""
367 else:
368 exe = Utilities.getExecutablePath(exe)
369 if exe:
370 if versionCommand and \
371 (versionStartsWith != "" or
372 (versionRe is not None and versionRe != "")) and \
373 versionPosition:
374 proc = QProcess()
375 proc.setProcessChannelMode(QProcess.MergedChannels)
376 if exeModule:
377 args = exeModule[:] + [versionCommand]
378 else:
379 args = [versionCommand]
380 proc.start(exe, args)
381 finished = proc.waitForFinished(10000)
382 if finished:
383 output = str(proc.readAllStandardOutput(),
384 Preferences.getSystem("IOEncoding"),
385 'replace')
386 if exeModule and exeModule[0] == "-m" and \
387 ("ImportError:" in output or
388 "ModuleNotFoundError:" in output or
389 proc.exitCode() != 0):
390 version = self.tr("(module not found)")
391 else:
392 if versionRe is None:
393 versionRe = "^{0}".format(
394 re.escape(versionStartsWith))
395 versionRe = re.compile(versionRe, re.UNICODE)
396 for line in output.splitlines():
397 if versionRe.search(line):
398 try:
399 version = line.split()[versionPosition]
400 if versionCleanup:
401 version = version[
402 versionCleanup[0]:
403 versionCleanup[1]
404 ]
405 break
406 except IndexError:
407 version = self.tr("(unknown)")
408 else:
409 version = self.tr("(unknown)")
410 else:
411 version = self.tr("(not executable)")
412 if exeModule:
413 QTreeWidgetItem(itm, [
414 "{0} {1}".format(exe, " ".join(exeModule)),
415 version])
416 else:
417 QTreeWidgetItem(itm, [exe, version])
418 itm.setExpanded(True)
419 else:
420 if itm.childCount() == 0:
421 itm.setText(1, self.tr("(not found)"))
422 else:
423 QTreeWidgetItem(itm, [rememberedExe,
424 self.tr("(not found)")])
425 itm.setExpanded(True)
426 QApplication.processEvents()
427 self.programsList.header().resizeSections(QHeaderView.ResizeToContents)
428 self.programsList.header().setStretchLastSection(True)
429 return version
430
431 def __createEntry(self, description, entryText, entryVersion):
432 """
433 Private method to generate a program entry.
434
435 @param description descriptive text (string)
436 @param entryText text to show (string)
437 @param entryVersion version string to show (string).
438 """
439 itm = QTreeWidgetItem(self.programsList, [description])
440 font = itm.font(0)
441 font.setBold(True)
442 itm.setFont(0, font)
443
444 if len(entryVersion):
445 QTreeWidgetItem(itm, [entryText, entryVersion])
446 itm.setExpanded(True)
447 else:
448 itm.setText(1, self.tr("(not found)"))
449 QApplication.processEvents()
450 self.programsList.header().resizeSections(QHeaderView.ResizeToContents)
451 self.programsList.header().setStretchLastSection(True)

eric ide

mercurial