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

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

"""
Module implementing a dialog for the configuration of eric4.
"""

import os

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from KdeQt import KQMessageBox

import QScintilla.Lexers

import Preferences

from Ui_ConfigurationDialog import Ui_ConfigurationDialog

from PreferencesLexer import PreferencesLexer
import UI.PixmapCache

from eric4config import getConfig

class ConfigurationPageItem(QTreeWidgetItem):
    """
    Class implementing a QTreeWidgetItem holding the configuration page data.
    """
    def __init__(self, parent, text, pageName, iconFile):
        """
        Constructor
        
        @param parent parent widget of the item (QTreeWidget or QTreeWidgetItem)
        @param text text to be displayed (string or QString)
        @param pageName name of the configuration page (string or QString)
        @param iconFile file name of the icon to be shown (string)
        """
        QTreeWidgetItem.__init__(self, parent, QStringList(text))
        self.setIcon(0, UI.PixmapCache.getIcon(iconFile))
        
        self.__pageName = unicode(pageName)
        
    def getPageName(self):
        """
        Public method to get the name of the associated configuration page.
        
        @return name of the configuration page (string)
        """
        return self.__pageName

class ConfigurationDialog(QDialog, Ui_ConfigurationDialog):
    """
    Class implementing a dialog for the configuration of eric4.
    """
    def __init__(self, parent = None, name = None, modal = False, fromEric = True):
        """
        Constructor
        
        @param parent The parent widget of this dialog. (QWidget)
        @param name The name of this dialog. (QString)
        @param modal Flag indicating a modal dialog. (boolean)
        @param fromEric flag indicating a dialog generation from within the 
            eric4 ide (boolean)
        """
        QDialog.__init__(self,parent)
        if name:
            self.setObjectName(name)
        self.setModal(modal)
        self.setupUi(self)
        
        self.fromEric = fromEric
        if not fromEric:
            self.buttonBox.button(QDialogButtonBox.Apply).hide()
        self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(False)
        self.buttonBox.button(QDialogButtonBox.Reset).setEnabled(False)
        
        self.configList.header().hide()
        self.configList.header().setSortIndicator(0, Qt.AscendingOrder)
        
        self.itmDict = {}
        
        ericPic = QPixmap(os.path.join(getConfig('ericPixDir'), 'eric.png'))
        self.emptyPagePixmap.setPixmap(ericPic)
        self.emptyPage = self.configStack.findChildren(QWidget, "emptyPage")[0]
        self.configStack.setCurrentWidget(self.emptyPage)
        
        self.configItems = {
            # key : [display string, pixmap name, dialog module name, parent key,
            #        reference to configuration page (must always be last)]
            # The dialog module must have the module function create to create
            # the configuration page. This must have the method save to save 
            # the settings.
            "applicationPage" : \
                [self.trUtf8("Application"), "preferences-application.png",
                 "ApplicationPage", None, None],
            "corbaPage" : \
                [self.trUtf8("CORBA"), "preferences-orbit.png",
                "CorbaPage", None, None],
            "emailPage" : \
                [self.trUtf8("Email"), "preferences-mail_generic.png",
                "EmailPage", None, None],
            "graphicsPage" : \
                [self.trUtf8("Graphics"), "preferences-graphics.png",
                "GraphicsPage", None, None],
            "iconsPage" : \
                [self.trUtf8("Icons"), "preferences-icons.png",
                "IconsPage", None, None],
            "interfacePage" : \
                [self.trUtf8("Interface"), "preferences-interface.png",
                "InterfacePage", None, None],
            "printerPage" : \
                [self.trUtf8("Printer"), "preferences-printer.png",
                "PrinterPage", None, None],
            "pythonPage" : \
                [self.trUtf8("Python"), "preferences-python.png",
                "PythonPage", None, None],
            "qtPage" : \
                [self.trUtf8("Qt"), "preferences-qtlogo.png",
                "QtPage", None, None],
            "refactoringPage" : \
                [self.trUtf8("Refactoring"), "preferences-refactoring.png",
                "RefactoringPage", None, None],
            "shellPage" : \
                [self.trUtf8("Shell"), "preferences-shell.png",
                "ShellPage", None, None],
            "tasksPage" : \
                [self.trUtf8("Tasks"), "task.png",
                "TasksPage", None, None],
            "templatesPage" : \
                [self.trUtf8("Templates"), "preferences-template.png",
                "TemplatesPage", None, None],
            "vcsPage" : \
                [self.trUtf8("Version Control Systems"), "preferences-vcs.png",
                "VcsPage", None, None],
            "viewmanagerPage" : \
                [self.trUtf8("Viewmanager"), "preferences-viewmanager.png",
                "ViewmanagerPage", None, None],
            
            "0debuggerPage": \
                [self.trUtf8("Debugger"), "preferences-debugger.png",
                None, None, None],
            "debuggerGeneral1Page" : \
                [self.trUtf8("General (Part 1)"), "preferences-debugger.png",
                "DebuggerGeneral1Page", "0debuggerPage", None],
            "debuggerGeneral2Page" : \
                [self.trUtf8("General (Part 2)"), "preferences-debugger.png",
                "DebuggerGeneral2Page", "0debuggerPage", None],
            "debuggerPythonPage" : \
                [self.trUtf8("Python"), "preferences-pyDebugger.png",
                "DebuggerPythonPage", "0debuggerPage", None],
            "debuggerRubyPage" : \
                [self.trUtf8("Ruby"), "preferences-rbDebugger.png",
                "DebuggerRubyPage", "0debuggerPage", None],
            
            "0editorPage" : \
                [self.trUtf8("Editor"), "preferences-editor.png",
                None, None, None],
            "editorAPIsPage" : \
                [self.trUtf8("APIs"), "preferences-api.png",
                "EditorAPIsPage", "0editorPage", None],
            "editorAutocompletionPage" : \
                [self.trUtf8("Autocompletion"), "preferences-autocompletion.png",
                "EditorAutocompletionPage", "0editorPage", None],
            "editorCalltipsPage" : \
                [self.trUtf8("Calltips"), "preferences-calltips.png",
                "EditorCalltipsPage", "0editorPage", None],
            "editorColoursPage" : \
                [self.trUtf8("Colours"), "preferences-colours.png",
                "EditorColoursPage", "0editorPage", None],
            "editorGeneralPage" : \
                [self.trUtf8("General"), "preferences-general.png",
                "EditorGeneralPage", "0editorPage", None],
            "editorHighlightersPage" : \
                [self.trUtf8("Highlighter Association"), 
                "preferences-highlighter-association.png",
                "EditorHighlightersPage", "0editorPage", None],
            "editorHighlightingStylesPage" : \
                [self.trUtf8("Highlighting Styles"), 
                "preferences-highlighting-styles.png",
                "EditorHighlightingStylesPage", "0editorPage", None],
            "editorProperties1Page" : \
                [self.trUtf8("Properties (Part 1)"), "preferences-properties.png",
                "EditorProperties1Page", "0editorPage", None],
            "editorProperties2Page" : \
                [self.trUtf8("Properties (Part 2)"), "preferences-properties.png",
                "EditorProperties2Page", "0editorPage", None],
            "editorStylesPage" : \
                [self.trUtf8("Style"), "preferences-styles.png",
                "EditorStylesPage", "0editorPage", None],
            "editorTypingPage" : \
                [self.trUtf8("Typing"), "preferences-typing.png",
                "EditorTypingPage", "0editorPage", None],
            
            "0helpPage" : \
                [self.trUtf8("Help"), "preferences-help.png",
                None, None, None],
            "helpDocumentationPage" : \
                [self.trUtf8("Help Documentation"), "preferences-helpdocumentation.png",
                "HelpDocumentationPage", "0helpPage", None],
            "helpViewersPage" : \
                [self.trUtf8("Help Viewers"), "preferences-helpviewers.png",
                "HelpViewersPage", "0helpPage", None],
            
            "0projectPage" : \
                [self.trUtf8("Project"), "preferences-project.png",
                None, None, None],
            "projectBrowserPage" : \
                [self.trUtf8("Project Viewer"), "preferences-project.png",
                "ProjectBrowserPage", "0projectPage", None],
            "projectPage" : \
                [self.trUtf8("Project"), "preferences-project.png",
                "ProjectPage", "0projectPage", None],
        }
        
        # generate the list entries
        keys = self.configItems.keys()
        keys.sort()
        for key in keys:
            pageData = self.configItems[key]
            if pageData[3]:
                pitm = self.itmDict[pageData[3]] # get the parent item
            else:
                pitm = self.configList
            self.itmDict[key] = ConfigurationPageItem(pitm, pageData[0], key, pageData[1])
            if pitm != self.configList:
                self.configList.setItemExpanded(pitm, True)
        self.configList.sortByColumn(0, Qt.AscendingOrder)
        
        # set the initial size of the splitter
        self.configSplitter.setSizes([200, 600])
        
        self.connect(self.configList, SIGNAL("itemActivated(QTreeWidgetItem *, int)"),
            self.__showConfigurationPage)
        self.connect(self.configList, SIGNAL("itemClicked(QTreeWidgetItem *, int)"),
            self.__showConfigurationPage)
        
        self.__initLexers()
        
    def __initLexers(self):
        """
        Private method to initialize the dictionary of preferences lexers.
        """
        self.lexers = {}
        for language in QScintilla.Lexers.getSupportedLanguages().keys():
            self.lexers[language] = PreferencesLexer(language, self)
        
    def __importConfigurationPage(self, name):
        """
        Private method to import a configuration page module.
        
        @param name name of the configuration page module (string)
        @return reference to the configuration page module
        """
        modName = "Preferences.ConfigurationPages.%s" % name
        try:
            mod = __import__(modName)
            components = modName.split('.')
            for comp in components[1:]:
                mod = getattr(mod, comp)
            return mod
        except ImportError:
            KQMessageBox.critical(None,
                self.trUtf8("Configuration Page Error"),
                self.trUtf8("""<p>The configuration page <b>%1</b>"""
                            """ could not be loaded.</p>""").arg(name))
            return None
        
    def __showConfigurationPage(self, itm, column):
        """
        Private slot to show a selected configuration page.
        
        @param itm reference to the selected item (QTreeWidgetItem)
        @param column column that was selected (integer) (ignored)
        """
        pageName = itm.getPageName()
        self.showConfigurationPageByName(pageName)
        
    def __initPage(self, pageData):
        """
        Private method to initialize a configuration page.
        
        @param pageData data structure for the page to initialize
        @return reference to the initialized page
        """
        page = None
        mod = self.__importConfigurationPage(pageData[2])
        if mod:
            page = mod.create(self)
            self.configStack.addWidget(page)
            pageData[-1] = page
        return page
        
    def showConfigurationPageByName(self, pageName):
        """
        Public slot to show a named configuration page.
        
        @param pageName name of the configuration page to show (string or QString)
        """
        pageName = unicode(pageName)
        pageData = self.configItems[pageName]
        if pageData[-1] is None and pageData[2] is not None:
            # the page was not loaded yet, create it
            page = self.__initPage(pageData)
        else:
            page = pageData[-1]
        if page is None:
            page = self.emptyPage
        self.configStack.setCurrentWidget(page)
        if page != self.emptyPage:
            page.polishPage()
            self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(True)
            self.buttonBox.button(QDialogButtonBox.Reset).setEnabled(True)
        else:
            self.buttonBox.button(QDialogButtonBox.Apply).setEnabled(False)
            self.buttonBox.button(QDialogButtonBox.Reset).setEnabled(False)
        
    def calledFromEric(self):
        """
        Public method to check, if invoked from within eric.
        
        @return flag indicating invocation from within eric (boolean)
        """
        return self.fromEric
        
    def getPage(self, pageName):
        """
        Public method to get a reference to the named page.
        
        @param pageName name of the configuration page (string)
        @return reference to the page or None, indicating page was
            not loaded yet
        """
        return self.configItems[pageName][-1]
        
    def getLexers(self):
        """
        Public method to get a reference to the lexers dictionary.
        
        @return reference to the lexers dictionary
        """
        return self.lexers
        
    def setPreferences(self):
        """
        Public method called to store the selected values into the preferences storage.
        """
        for key, pageData in self.configItems.items():
            if pageData[-1]:
                pageData[-1].save()
                # page was loaded (and possibly modified)
                QApplication.processEvents()    # ensure HMI is responsive
        
    def accept(self):
        """
        Protected slot called by the Ok button. 
        """
        if not self.fromEric:
            self.setPreferences()
            Preferences.saveResetLayout()
            Preferences.syncPreferences()
        QDialog.accept(self)
        
    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.buttonBox.button(QDialogButtonBox.Apply):
            self.on_applyButton_clicked()
        elif button == self.buttonBox.button(QDialogButtonBox.Reset):
            self.on_resetButton_clicked()
        
    @pyqtSignature("")
    def on_applyButton_clicked(self):
        """
        Private slot called to apply the settings of the current page.
        """
        if self.configStack.currentWidget() != self.emptyPage:
            page = self.configStack.currentWidget()
            page.save()
            self.emit(SIGNAL('preferencesChanged'))
        
    @pyqtSignature("")
    def on_resetButton_clicked(self):
        """
        Private slot called to reset the settings of the current page.
        """
        if self.configStack.currentWidget() != self.emptyPage:
            currentPage = self.configStack.currentWidget()
            savedState = currentPage.saveState()
            pageName = self.configList.currentItem().getPageName()
            self.configStack.removeWidget(currentPage)
            if pageName == "editorHighlightingStylesPage":
                self.__initLexers()
            pageData = self.configItems[unicode(pageName)]
            pageData[-1] = None
            
            self.showConfigurationPageByName(pageName)
            if savedState is not None:
                self.configStack.currentWidget().setState(savedState)
