# -*- coding: utf-8 -*-

# Copyright (c) 2006 - 2007 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the Programs page.
"""

import os
import sys

from PyQt4.QtCore import pyqtSignature, QString, QStringList, Qt, QProcess
from PyQt4.QtGui import QApplication, QTreeWidgetItem, QHeaderView, QCursor, \
    QDialog, QDialogButtonBox

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)
        """
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.setObjectName("ProgramsDialog")
        
        self.__hasSearched = False
        
        self.searchButton = \
            self.buttonBox.addButton(self.trUtf8("Search"), QDialogButtonBox.ActionRole)
        self.searchButton.setToolTip(self.trUtf8("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()
        
    @pyqtSignature("")
    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 Qt programs
        disableQt3 = Preferences.getQt("DisableQt3")
        if not disableQt3:
            qtdir = Preferences.getQtDir()
            # 1a. Translation Converter
            exe = sys.platform == "win32" and \
                "%s.exe" % Utilities.generateQtToolName("lrelease", True) or \
                Utilities.generateQtToolName("lrelease", True)
            if qtdir:
                exe = os.path.join(qtdir, 'bin', exe)
            version = \
                self.__createProgramEntry(self.trUtf8("Translation Converter (Qt3)"), 
                    exe, '-version', 'lrelease', -1)
            # 1b. Qt Designer
            exe = sys.platform == "win32" and \
                "%s.exe" % Utilities.generateQtToolName("designer", True) or \
                Utilities.generateQtToolName("designer", True)
            if qtdir:
                exe = os.path.join(qtdir, 'bin', exe)
            self.__createProgramEntry(self.trUtf8("Qt3 Designer"), exe, version = version)
            # 1c. Qt Linguist
            exe = sys.platform == "win32" and \
                "%s.exe" % Utilities.generateQtToolName("linguist", True) or \
                Utilities.generateQtToolName("linguist", True)
            if qtdir:
                exe = os.path.join(qtdir, 'bin', exe)
            self.__createProgramEntry(self.trUtf8("Qt3 Linguist"), exe, version = version)
            # 1d. Qt Assistant
            exe = sys.platform == "win32" and \
                "%s.exe" % Utilities.generateQtToolName("assistant", True) or \
                Utilities.generateQtToolName("assistant", True)
            if qtdir:
                exe = os.path.join(qtdir, 'bin', exe)
            self.__createProgramEntry(self.trUtf8("Qt3 Assistant"), exe, 
                version = version)
        
        # do the Qt4 programs
        # 1e. Translation Converter
        exe = sys.platform == "win32" and \
            "%s.exe" % Utilities.generateQtToolName("lrelease") or \
            Utilities.generateQtToolName("lrelease")
        version = self.__createProgramEntry(self.trUtf8("Translation Converter (Qt4)"), 
                    exe, '-version', 'lrelease', -1)
        # 1f. Qt4 Designer
        exe = sys.platform == "win32" and \
            "%s.exe" % Utilities.generateQtToolName("designer") or \
            Utilities.generateQtToolName("designer")
        self.__createProgramEntry(self.trUtf8("Qt4 Designer"), exe, version = version)
        # 1g. Qt4 Linguist
        exe = sys.platform == "win32" and \
            "%s.exe" % Utilities.generateQtToolName("linguist") or \
            Utilities.generateQtToolName("linguist")
        self.__createProgramEntry(self.trUtf8("Qt4 Linguist"), exe, version = version)
        # 1h. Qt4 Assistant
        exe = sys.platform == "win32" and \
            "%s.exe" % Utilities.generateQtToolName("assistant") or \
            Utilities.generateQtToolName("assistant")
        self.__createProgramEntry(self.trUtf8("Qt4 Assistant"), exe, version = version)
        
        # 2. do the PyQt programs
        if not disableQt3:
            # 2a. Translation Extractor
            self.__createProgramEntry(self.trUtf8("Translation Extractor (Python, Qt3)"), 
                sys.platform == "win32" and "pylupdate.exe" or "pylupdate", 
                '-version', 'pylupdate', -1)
            # 2b. Forms Compiler
            self.__createProgramEntry(self.trUtf8("Forms Compiler (Python, Qt3)"), 
                sys.platform == "win32" and "pyuic.exe" or "pyuic", 
                '-version', 'Python User', 4)
        # 2c. Translation Extractor PyQt4
        self.__createProgramEntry(self.trUtf8("Translation Extractor (Python, Qt4)"), 
            sys.platform == "win32" and "pylupdate4.exe" or "pylupdate4", 
            '-version', 'pylupdate', -1)
        # 2d. Forms Compiler PyQt4
        self.__createProgramEntry(self.trUtf8("Forms Compiler (Python, Qt4)"), 
            sys.platform == "win32" and "pyuic4.bat" or "pyuic4", 
            '--version', 'Python User', 4)
        # 2e. Resource Compiler PyQt4
        self.__createProgramEntry(self.trUtf8("Resource Compiler (Python, Qt4)"), 
            sys.platform == "win32" and "pyrcc4.exe" or "pyrcc4", 
            '-version', 'Resource Compiler', -1)
        
        # 3. do the Ruby programs
        if not disableQt3:
            # 3a. Forms Compiler
            self.__createProgramEntry(self.trUtf8("Forms Compiler (Ruby, Qt3)"), 
                sys.platform == "win32" and "rbuic.exe" or "rbuic", 
                '-version', 'QtRuby User', 4)
        # 3b. Forms Compiler for Qt4
        self.__createProgramEntry(self.trUtf8("Forms Compiler (Ruby, Qt4)"), 
            sys.platform == "win32" and "rbuic4.exe" or "rbuic4", 
            '-version', 'Qt', -1)
        # 3b. Resource Compiler for Qt4
        self.__createProgramEntry(self.trUtf8("Resource Compiler (Ruby, Qt4)"), 
            sys.platform == "win32" and "rbrcc.exe" or "rbrcc", 
            '-version', 'Ruby Resource Compiler', -1)
        
        # 4. do the Eric4 programs
        # 4a. API File Generator
        self.__createProgramEntry(self.trUtf8("Eric4 API File Generator"), 
            sys.platform == "win32" and "eric4-api.bat" or "eric4-api", 
            '--version', 'eric4-', -2)
        # 4b. Documentation Generator
        self.__createProgramEntry(self.trUtf8("Eric4 Documentation Generator"), 
            sys.platform == "win32" and "eric4-doc.bat" or "eric4-doc", 
            '--version', 'eric4-', -2)
        # 4c. Translation Previewer
        self.__createProgramEntry(self.trUtf8("Eric4 Translation Previewer"), 
            sys.platform == "win32" and "eric4-trpreviewer.bat" or "eric4-trpreviewer", 
            '--version', 'Eric4', -2)
        # 4d. Forms Previewer
        self.__createProgramEntry(self.trUtf8("Eric4 Forms Previewer"), 
            sys.platform == "win32" and "eric4-uipreviewer.bat" or "eric4-uipreviewer", 
            '--version', 'Eric4', -2)
        
        # 5. do the CORBA programs
        # 5a. omniORB
        exe = unicode(Preferences.getCorba("omniidl"))
        if sys.platform == "win32":
            exe += ".exe"
        self.__createProgramEntry(self.trUtf8("CORBA IDL Compiler"), exe,
            '-V', 'omniidl', -1)
        
        # 6. do the Version Control programs
        # 6a. CVS
        self.__createProgramEntry(self.trUtf8("Version Control - CVS"), 
            sys.platform == "win32" and "cvs.exe" or "cvs", 
            '--version', 'Concurrent Versions', 4)
        # 6b. Subversion
        self.__createProgramEntry(self.trUtf8("Version Control - Subversion"), 
            sys.platform == "win32" and "svn.exe" or "svn", 
            '--version', 'svn', 2)
        # 6c. Subversion - PySvn
        try:
            import pysvn
            try:
                entryText = os.path.dirname(pysvn.__file__)
            except AttributeError:
                entryText = "PySvn"
            self.__createEntry(self.trUtf8("Version Control - Subversion (Python)"),
                entryText, ".".join([str(v) for v in pysvn.version]))
        except ImportError:
            self.__createEntry(self.trUtf8("Version Control - Subversion (Python)"),
                "PySvn", "")
        
        # 7. do the Checker programs
        # 7a. Pylint
        exe = 'pylint'
        if sys.platform == "win32":
            exe = os.path.join(sys.exec_prefix, "Scripts", exe + '.bat')
        self.__createProgramEntry(self.trUtf8("Checkers - Pylint"), exe, 
            '--version', 'pylint', -1, versionCleanup = (0, -1))
        
        # 8. do the Packagers programs
        # 8a. cx_freeze
        self.__createProgramEntry(self.trUtf8("Packagers - cx_freeze"), 
            sys.platform == "win32" and "FreezePython.exe" or "FreezePython", 
            '--version', 'FreezePython', -1)
        
        self.programsList.sortByColumn(0, Qt.AscendingOrder)
        QApplication.restoreOverrideCursor()
        
        self.__hasSearched = True

    def __createProgramEntry(self, description, exe,
                             versionCommand = "", versionStartsWith = "", 
                             versionPosition = 0, version = "",
                             versionCleanup = None):
        """
        Private method to generate a program entry.
        
        @param description descriptive text (string or QString)
        @param exe name of the executable program (string)
        @param versionCommand command line switch to get the version info (string)
            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)
        @return version string of detected or given version (string)
        """
        itm = QTreeWidgetItem(self.programsList, QStringList(description))
        font = itm.font(0)
        font.setBold(True)
        itm.setFont(0, font)
        if not exe:
            itm.setText(1, self.trUtf8("(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 and versionPosition:
                    proc = QProcess()
                    proc.setProcessChannelMode(QProcess.MergedChannels)
                    proc.start(exe, QStringList(versionCommand))
                    finished = proc.waitForFinished(10000)
                    if finished:
                        output = \
                            unicode(proc.readAllStandardOutput(), 
                                    str(Preferences.getSystem("IOEncoding")), 
                                    'replace')
                        for line in output.splitlines():
                            if line.startswith(versionStartsWith):
                                version = line.split()[versionPosition]
                                if versionCleanup:
                                    version = version[versionCleanup[0]:versionCleanup[1]]
                                break
                    else:
                        version = self.trUtf8("(not executable)")
                itm2 = QTreeWidgetItem(itm, QStringList() << exe << version)
                self.programsList.setItemExpanded(itm, True)
            else:
                itm.setText(1, self.trUtf8("(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 or QString)
        @param entryText text to show (string or QString)
        @param entryVersion version string to show (string or QString).
        """
        itm = QTreeWidgetItem(self.programsList, QStringList(description))
        font = itm.font(0)
        font.setBold(True)
        itm.setFont(0, font)
        
        if entryVersion:
            itm2 = QTreeWidgetItem(itm, QStringList() << entryText << entryVersion)
            self.programsList.setItemExpanded(itm, True)
        else:
            itm.setText(1, self.trUtf8("(not found)"))
        QApplication.processEvents()
        self.programsList.header().resizeSections(QHeaderView.ResizeToContents)
        self.programsList.header().setStretchLastSection(True)
