Thu, 10 Jan 2019 14:18:48 +0100
Updated copyright for 2019.
# -*- coding: utf-8 -*- # Copyright (c) 2006 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the Programs page. """ from __future__ import unicode_literals try: str = unicode except NameError: pass import os import re import sys from PyQt5.QtCore import pyqtSlot, Qt, QProcess from PyQt5.QtGui import QCursor from PyQt5.QtWidgets import QApplication, QTreeWidgetItem, QHeaderView, \ QDialog, QDialogButtonBox from E5Gui.E5Application import e5App from .Ui_ProgramsDialog import Ui_ProgramsDialog import Preferences import Utilities class ProgramsDialog(QDialog, Ui_ProgramsDialog): """ Class implementing the Programs page. """ def __init__(self, parent=None): """ Constructor @param parent The parent widget of this dialog. (QWidget) """ super(ProgramsDialog, self).__init__(parent) self.setupUi(self) self.setObjectName("ProgramsDialog") self.setWindowFlags(Qt.Window) self.__hasSearched = False self.programsList.headerItem().setText( self.programsList.columnCount(), "") self.searchButton = self.buttonBox.addButton( self.tr("Search"), QDialogButtonBox.ActionRole) self.searchButton.setToolTip( self.tr("Press to search for programs")) def show(self): """ Public slot to show the dialog. """ QDialog.show(self) if not self.__hasSearched: self.on_programsSearchButton_clicked() def on_buttonBox_clicked(self, button): """ Private slot called by a button of the button box clicked. @param button button that was clicked (QAbstractButton) """ if button == self.searchButton: self.on_programsSearchButton_clicked() @pyqtSlot() def on_programsSearchButton_clicked(self): """ Private slot to search for all supported/required programs. """ QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) QApplication.processEvents() self.programsList.clear() header = self.programsList.header() header.setSortIndicator(0, Qt.AscendingOrder) header.setSortIndicatorShown(False) # 1. do the Qt4/Qt5 programs # 1a. Translation Converter exe = Utilities.isWindowsPlatform() and \ "{0}.exe".format(Utilities.generateQtToolName("lrelease")) or \ Utilities.generateQtToolName("lrelease") exe = os.path.join(Utilities.getQtBinariesPath(), exe) version = self.__createProgramEntry( self.tr("Translation Converter (Qt)"), exe, '-version', 'lrelease', -1) # 1b. Qt Designer if Utilities.isWindowsPlatform(): exe = os.path.join( Utilities.getQtBinariesPath(), "{0}.exe".format(Utilities.generateQtToolName("designer"))) elif Utilities.isMacPlatform(): exe = Utilities.getQtMacBundle("designer") else: exe = os.path.join( Utilities.getQtBinariesPath(), Utilities.generateQtToolName("designer")) self.__createProgramEntry( self.tr("Qt Designer"), exe, version=version) # 1c. Qt Linguist if Utilities.isWindowsPlatform(): exe = os.path.join( Utilities.getQtBinariesPath(), "{0}.exe".format(Utilities.generateQtToolName("linguist"))) elif Utilities.isMacPlatform(): exe = Utilities.getQtMacBundle("linguist") else: exe = os.path.join( Utilities.getQtBinariesPath(), Utilities.generateQtToolName("linguist")) self.__createProgramEntry( self.tr("Qt Linguist"), exe, version=version) # 1d. Qt Assistant if Utilities.isWindowsPlatform(): exe = os.path.join( Utilities.getQtBinariesPath(), "{0}.exe".format(Utilities.generateQtToolName("assistant"))) elif Utilities.isMacPlatform(): exe = Utilities.getQtMacBundle("assistant") else: exe = os.path.join( Utilities.getQtBinariesPath(), Utilities.generateQtToolName("assistant")) self.__createProgramEntry( self.tr("Qt Assistant"), exe, version=version) # 2. do the PyQt programs # 2.1 do the PyQt4 programs # 2.1a. Translation Extractor PyQt4 self.__createProgramEntry( self.tr("Translation Extractor (Python, PyQt4)"), Utilities.generatePyQtToolPath("pylupdate4"), '-version', 'pylupdate', -1) # 2.1b. Forms Compiler PyQt4 self.__createProgramEntry( self.tr("Forms Compiler (Python, PyQt4)"), Utilities.generatePyQtToolPath("pyuic4", ["py3uic4", "py2uic4"]), '--version', 'Python User', 4) # 2.1c. Resource Compiler PyQt4 self.__createProgramEntry( self.tr("Resource Compiler (Python, PyQt4)"), Utilities.generatePyQtToolPath("pyrcc4"), '-version', 'Resource Compiler', -1) # 2.2 do the PyQt5 programs # 2.2a. Translation Extractor PyQt5 self.__createProgramEntry( self.tr("Translation Extractor (Python, PyQt5)"), Utilities.generatePyQtToolPath("pylupdate5"), '-version', 'pylupdate', -1) # 2.2b. Forms Compiler PyQt5 self.__createProgramEntry( self.tr("Forms Compiler (Python, PyQt5)"), Utilities.generatePyQtToolPath("pyuic5", ["py3uic5", "py2uic5"]), '--version', 'Python User', 4) # 2.2c. Resource Compiler PyQt5 self.__createProgramEntry( self.tr("Resource Compiler (Python, PyQt5)"), Utilities.generatePyQtToolPath("pyrcc5"), '-version', '', -1, versionRe='Resource Compiler|pyrcc5') # 3.1 do the PySide programs # 3.1a. Translation Extractor PySide self.__createProgramEntry( self.tr("Translation Extractor (Python, PySide)"), Utilities.generatePySideToolPath("pyside-lupdate", "1"), '-version', '', -1, versionRe='lupdate') # 3.1b. Forms Compiler PySide self.__createProgramEntry( self.tr("Forms Compiler (Python, PySide)"), Utilities.generatePySideToolPath("pyside-uic", "1"), '--version', 'PySide User', 5, versionCleanup=(0, -1)) # 3.1c Resource Compiler PySide self.__createProgramEntry( self.tr("Resource Compiler (Python, PySide)"), Utilities.generatePySideToolPath("pyside-rcc", "1"), '-version', 'Resource Compiler', -1) # 3.2 do the PySide2 programs # 3.2a. Translation Extractor PySide2 self.__createProgramEntry( self.tr("Translation Extractor (Python, PySide2)"), Utilities.generatePySideToolPath("pyside2-lupdate", "2"), '-version', '', -1, versionRe='lupdate') # 3.2b. Forms Compiler PySide2 self.__createProgramEntry( self.tr("Forms Compiler (Python, PySide2)"), Utilities.generatePySideToolPath("pyside2-uic", "2"), '--version', 'PySide2 User', -1, versionCleanup=(0, -1)) # 3.2c Resource Compiler PySide2 self.__createProgramEntry( self.tr("Resource Compiler (Python, PySide2)"), Utilities.generatePySideToolPath("pyside2-rcc", "2"), '-version', 'Resource Compiler', -1) # 4. do the Ruby programs # 4a. Forms Compiler for Qt4 self.__createProgramEntry( self.tr("Forms Compiler (Ruby, Qt4)"), Utilities.isWindowsPlatform() and "rbuic4.exe" or "rbuic4", '-version', 'Qt', -1) # 4b. Resource Compiler for Qt4 self.__createProgramEntry( self.tr("Resource Compiler (Ruby, Qt4)"), Utilities.isWindowsPlatform() and "rbrcc.exe" or "rbrcc", '-version', 'Ruby Resource Compiler', -1) # 5. do the CORBA and Protobuf programs # 5a. omniORB exe = Preferences.getCorba("omniidl") if not exe: exe = "omniidl" if Utilities.isWindowsPlatform(): exe += ".exe" self.__createProgramEntry( self.tr("CORBA IDL Compiler"), exe, '-V', 'omniidl', -1) # 5b. protobuf exe = Preferences.getProtobuf("protoc") if not exe: exe = "protoc" if Utilities.isWindowsPlatform(): exe += ".exe" self.__createProgramEntry( self.tr("Protobuf Compiler"), exe, '--version', 'libprotoc', -1) # 5c. grpc exe = Preferences.getProtobuf("grpcPython") if not exe: exe = sys.executable self.__createProgramEntry( self.tr("gRPC Compiler"), exe, '--version', 'libprotoc', -1, exeModule=['-m', 'grpc_tools.protoc']) # 6. do the spell checking entry try: import enchant try: text = os.path.dirname(enchant.__file__) except AttributeError: text = "enchant" try: version = enchant.__version__ except AttributeError: version = self.tr("(unknown)") except (ImportError, AttributeError, OSError): text = "enchant" version = "" self.__createEntry( self.tr("Spell Checker - PyEnchant"), text, version) # 7. do the pygments entry try: import pygments try: text = os.path.dirname(pygments.__file__) except AttributeError: text = "pygments" try: version = pygments.__version__ except AttributeError: version = self.tr("(unknown)") except (ImportError, AttributeError, OSError): text = "pygments" version = "" self.__createEntry( self.tr("Source Highlighter - Pygments"), text, version) # do the plugin related programs pm = e5App().getObject("PluginManager") for info in pm.getPluginExeDisplayData(): if info["programEntry"]: if "exeModule" not in info: info["exeModule"] = None if "versionRe" not in info: info["versionRe"] = None self.__createProgramEntry( info["header"], info["exe"], versionCommand=info["versionCommand"], versionStartsWith=info["versionStartsWith"], versionPosition=info["versionPosition"], version=info["version"], versionCleanup=info["versionCleanup"], versionRe=info["versionRe"], exeModule=info["exeModule"], ) else: self.__createEntry( info["header"], info["text"], info["version"] ) self.programsList.sortByColumn(0, Qt.AscendingOrder) QApplication.restoreOverrideCursor() self.__hasSearched = True def __createProgramEntry(self, description, exe, versionCommand="", versionStartsWith="", versionPosition=0, version="", versionCleanup=None, versionRe=None, exeModule=None): """ Private method to generate a program entry. @param description descriptive text (string) @param exe name of the executable program (string) @param versionCommand command line switch to get the version info (str). If this is empty, the given version will be shown. @param versionStartsWith start of line identifying version info (string) @param versionPosition index of part containing the version info (integer) @keyparam version version string to show (string) @keyparam versionCleanup tuple of two integers giving string positions start and stop for the version string (tuple of integers) @keyparam versionRe regexp to determine the line identifying version info (string). Takes precedence over versionStartsWith. @keyparam exeModule list of command line parameters to execute a module with the program given in exe (e.g. to execute a Python module) (list of str) @return version string of detected or given version (string) """ itmList = self.programsList.findItems( description, Qt.MatchCaseSensitive) if itmList: itm = itmList[0] else: itm = QTreeWidgetItem(self.programsList, [description]) font = itm.font(0) font.setBold(True) itm.setFont(0, font) if not exe: itm.setText(1, self.tr("(not configured)")) else: if os.path.isabs(exe): if not Utilities.isExecutable(exe): exe = "" else: exe = Utilities.getExecutablePath(exe) if exe: if versionCommand and \ (versionStartsWith != "" or (versionRe is not None and versionRe != "")) and \ versionPosition: proc = QProcess() proc.setProcessChannelMode(QProcess.MergedChannels) if exeModule: args = exeModule[:] + [versionCommand] else: args = [versionCommand] proc.start(exe, args) finished = proc.waitForFinished(10000) if finished: output = str(proc.readAllStandardOutput(), Preferences.getSystem("IOEncoding"), 'replace') if exeModule and exeModule[0] == "-m" and \ ("ImportError:" in output or "ModuleNotFoundError:" in output): version = self.tr("(module not found)") else: if versionRe is None: versionRe = "^{0}".format( re.escape(versionStartsWith)) versionRe = re.compile(versionRe, re.UNICODE) for line in output.splitlines(): if versionRe.search(line): try: version = line.split()[versionPosition] if versionCleanup: version = version[ versionCleanup[0]: versionCleanup[1] ] break except IndexError: version = self.tr("(unknown)") else: version = self.tr("(unknown)") else: version = self.tr("(not executable)") if exeModule: QTreeWidgetItem(itm, [ "{0} {1}".format(exe, " ".join(exeModule)), version]) else: QTreeWidgetItem(itm, [exe, version]) itm.setExpanded(True) else: itm.setText(1, self.tr("(not found)")) QApplication.processEvents() self.programsList.header().resizeSections(QHeaderView.ResizeToContents) self.programsList.header().setStretchLastSection(True) return version def __createEntry(self, description, entryText, entryVersion): """ Private method to generate a program entry. @param description descriptive text (string) @param entryText text to show (string) @param entryVersion version string to show (string). """ itm = QTreeWidgetItem(self.programsList, [description]) font = itm.font(0) font.setBold(True) itm.setFont(0, font) if len(entryVersion): QTreeWidgetItem(itm, [entryText, entryVersion]) itm.setExpanded(True) else: itm.setText(1, self.tr("(not found)")) QApplication.processEvents() self.programsList.header().resizeSections(QHeaderView.ResizeToContents) self.programsList.header().setStretchLastSection(True)