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

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

"""
Module implementing a dialog to enter the parameters for happydoc.
"""

import sys
import os
import copy

from qt import *

from KdeQt import KQFileDialog, KQColorDialog

from HappydocConfigForm import HappydocConfigForm
import Utilities

class HappydocConfigDialog(HappydocConfigForm):
    """
    Class implementing a dialog to enter the parameters for happydoc.
    """
    def __init__(self,ppath,parms = None,parent = None):
        """
        Constructor
        
        @param ppath project path of the current project (string)
        @param parms parameters to set in the dialog
        @param parent parent widget of this dialog
        """
        HappydocConfigForm.__init__(self,parent,None,1)
        
        self.initializeDefaults()
        
        # get a copy of the defaults to store the user settings
        self.parameters = copy.deepcopy(self.defaults)
        
        # combine it with the values of parms
        if parms is not None:
            for key, value in parms.items():
                self.parameters[key] = parms[key]
        
        self.ppath = ppath
        
        # sequences used to convert the ids reported by the button groups
        # to the values needed for happydoc
        self.formats = ['Dia', 'HTMLTable', 'SGMLDocBook',
            'Text', 'docbookx', 'xpydoc']
        self.docsets = ['Dia', 'MultiFile', 'SingleFile', 'mstruct']
        self.syntaxes = ['StructuredText', 'ClassicStructuredText',
            'PlainText', 'RawText']
        
        #initialize the tabs
        
        # 1. the formatter tab
        self.formattersGroup.setButton(self.formats.index(self.parameters['format']))
        # initialize the colour displays
        pl = self.pbEdit.palette()
        pl.setColor(QColorGroup.Base, QColor(self.parameters['pageBackgroundColor']))
        
        pl = self.cfEdit.palette()
        pl.setColor(QColorGroup.Text, QColor(self.parameters['codeForegroundColor']))
        pl.setColor(QColorGroup.Base, QColor(self.parameters['pageBackgroundColor']))
        
        pl = self.l1hEdit.palette()
        pl.setColor(QColorGroup.Text, 
            QColor(self.parameters['levelOneHeadingForegroundColor']))
        pl.setColor(QColorGroup.Base, 
            QColor(self.parameters['levelOneHeadingBackgroundColor']))
        
        pl = self.l2hEdit.palette()
        pl.setColor(QColorGroup.Text, 
            QColor(self.parameters['levelTwoHeadingForegroundColor']))
        pl.setColor(QColorGroup.Base, 
            QColor(self.parameters['levelTwoHeadingBackgroundColor']))

        self.compactHTMLCheckBox.setChecked(self.parameters['compactHTML'])
        self.quoteHTMLCheckBox.setChecked(self.parameters['htmlQuoteText'])
        self.prefixEdit.setText(self.parameters['filenamePrefix'])
        self.datetimeStampCheckBox.setChecked(self.parameters['dateStampFiles'])
        
        # 2. the docset tab
        self.docsetGroup.setButton(self.docsets.index(self.parameters['docset_type']))
        self.commentsCheckBox.setChecked(self.parameters['includeComments'])
        self.privateCheckBox.setChecked(self.parameters['includePrivateNames'])
        self.packagesCheckBox.setChecked(self.parameters['usePackages'])
        self.recursionCheckBox.setChecked(self.parameters['useRecursion'])
        self.prewrittenEdit.setText(self.parameters['prewrittenFileBasenames'])
        self.titleEdit.setText(self.parameters['title'])
        
        # 3. the parser tab
        self.docstringGroup.setButton(\
            self.syntaxes.index(self.parameters['docStringFormat']))
            
        # 4. the various tab
        self.authorEdit.setText(self.parameters['author'])
        self.packageDescrFileEdit.setText(self.parameters['packageDescriptionFile'])
        self.outputDirEdit.setText(self.parameters['outputDirectory'])
        self.ignoreDirsListBox.clear()
        for d in self.parameters['ignoreDirectories']:
            self.ignoreDirsListBox.insertItem(d)
        
    def initializeDefaults(self):
        """
        Private method to set the default values. 
        
        These are needed later on to generate the commandline
        parameters.
        """
        self.defaults = {
            'format' : 'HTMLTable',
            'docset_type' : 'MultiFile',
            'docStringFormat' : 'StructuredText',
            
            #defaults for HTML output
            'compactHTML' : 0,
            'htmlQuoteText' : 1,
            'pageBackgroundColor' : '#ffffff',
            'levelOneHeadingBackgroundColor' : '#88bbee',
            'levelOneHeadingForegroundColor' : '#000000',
            'levelTwoHeadingBackgroundColor' : '#99ccff',
            'levelTwoHeadingForegroundColor' : '#000000',
            'codeForegroundColor' : '#000088',
            
            #defaults for all output
            'dateStampFiles' : 1,
            'filenamePrefix' : '',
            
            #defaults for docsets
            'includeComments' : 1,
            'includePrivateNames' : 1,
            'usePackages' : 1,
            'useRecursion' : 1,
            'prewrittenFileBasenames' : '',
            'title' : '',
            
            #defaults for the rest
            'author' : '',
            'packageDescriptionFile' : '',
            'outputDirectory' : '',
            'ignoreDirectories' : []
        }
        
    def generateParameters(self):
        """
        Public method that generates the commandline parameters.
        
        It generates a QStringList to be used
        to set the QProcess arguments for the happydoc call and
        a list containing the non default parameters. The second
        list can be passed back upon object generation to overwrite
        the default settings.
        
        @return a tuple of the commandline parameters and non default parameters
            (QStringList, dictionary)
        """
        parms = {}
        args = QStringList()
        
        # 1. the program name
        if sys.platform == "win32":
            args.append(sys.executable)
            args.append(Utilities.normjoinpath(sys.prefix, 'Scripts', 'happydocwin.py'))
        else:
            args.append('happydoc')
        
        # 2. the commandline options
        if self.parameters['author'] != self.defaults['author']:
            args.append('--author=%s' % self.parameters['author'])
            parms['author'] = self.parameters['author']
        if self.parameters['outputDirectory'] != self.defaults['outputDirectory']:
            args.append('-d')
            if os.path.isabs(self.parameters['outputDirectory']):
                args.append(self.parameters['outputDirectory'])
            else:
                args.append(os.path.join(self.ppath, self.parameters['outputDirectory']))
            parms['outputDirectory'] = self.parameters['outputDirectory']
        if self.parameters['ignoreDirectories'] != self.defaults['ignoreDirectories']:
            parms['ignoreDirectories'] = self.parameters['ignoreDirectories'][:]
            for d in self.parameters['ignoreDirectories']:
                args.append('-i')
                args.append(d)
        if self.parameters['packageDescriptionFile'] != self.defaults['packageDescriptionFile']:
            args.append('-p')
            args.append(self.parameters['packageDescriptionFile'])
            parms['packageDescriptionFile'] = self.parameters['packageDescriptionFile']
        if self.parameters['format'] != self.defaults['format']:
            args.append('-F')
            args.append(self.parameters['format'])
            parms['format'] = self.parameters['format']
        if self.parameters['docset_type'] != self.defaults['docset_type']:
            args.append('-T')
            args.append(self.parameters['docset_type'])
            parms['docset_type'] = self.parameters['docset_type']
                
        # 3. the formatter parameters
        if self.parameters['format'] == 'HTMLTable':
            for key in ['compactHTML', 'htmlQuoteText', 'pageBackgroundColor',
                'levelOneHeadingBackgroundColor', 'levelOneHeadingForegroundColor',
                'levelTwoHeadingBackgroundColor', 'levelTwoHeadingForegroundColor',
                'codeForegroundColor']:
                if self.parameters[key] != self.defaults[key]:
                    args.append('formatter_%s=%s' % (key, str(self.parameters[key])))
                    parms[key] = self.parameters[key]
        for key in ['compactHTML', 'htmlQuoteText', 'pageBackgroundColor',
            'levelOneHeadingBackgroundColor', 'levelOneHeadingForegroundColor',
            'levelTwoHeadingBackgroundColor', 'levelTwoHeadingForegroundColor',
            'codeForegroundColor']:
            if self.parameters[key] != self.defaults[key]:
                parms[key] = self.parameters[key]
                    
        if self.parameters['format'] in ['HTMLTable', 'Dia']:
            if self.parameters['dateStampFiles'] != self.defaults['dateStampFiles']:
                args.append(\
                    'formatter_dateStampFiles=%s' % str(self.parameters['dateStampFiles']))
                parms['dateStampFiles'] = self.parameters['dateStampFiles']
        if self.parameters['dateStampFiles'] != self.defaults['dateStampFiles']:
            parms['dateStampFiles'] = self.parameters['dateStampFiles']
            
        if self.parameters['format'] in ['HTMLTable', 'Dia', 'Text']:
            if self.parameters['filenamePrefix'] != self.defaults['filenamePrefix']:
                args.append('formatter_filenamePrefix=%s' % self.parameters['filenamePrefix'])
        if self.parameters['filenamePrefix'] != self.defaults['filenamePrefix']:
            parms['filenamePrefix'] = self.parameters['filenamePrefix']
            
        # 4. the docset parameters
        for key in ['includeComments', 'includePrivateNames', 'usePackages',
            'useRecursion', 'prewrittenFileBasenames', 'title']:
            if self.parameters[key] != self.defaults[key]:
                args.append('docset_%s=%s' % (key, str(self.parameters[key])))
                parms[key] = self.parameters[key]
        
        # 5. the parser parameters
        if self.parameters['docStringFormat'] != self.defaults['docStringFormat']:
            args.append('parser_docStringFormat=%s' % self.parameters['docStringFormat'])
            parms['docStringFormat'] = self.parameters['docStringFormat']
        
        return (args, parms)

    def selectBgColour(self, textedit, colour):
        """
        Private method used to select the background colour.

        It opens a KQColorDialog to select a colour and
        sets the background of the sample textedit.
        
        @return selected colour (string)
        """
        col = KQColorDialog.getColor(QColor(colour))
        if col.isValid():
            pl = textedit.palette()
            pl.setColor(QColorGroup.Base, col)
            textedit.repaint(1)
            return str(col.name())
        else:
            return colour
            
    def selectFgColour(self, textedit, colour):
        """
        Private method used to select the foreground colour.

        It opens a KQColorDialog to select a colour and
        sets the foreground of the sample textedit.
        
        @return selected colour (string)
        """
        col = KQColorDialog.getColor(QColor(colour))
        if col.isValid():
            pl = textedit.palette()
            pl.setColor(QColorGroup.Text, col)
            textedit.repaint(1)
            return str(col.name())
        else:
            return colour
            
    def handleFormatterSelected(self, id):
        """
        Private slot to handle the QButtonGroups clicked(int) signal.
        
        It sets the selected output formatter.
        
        @param id id of the selected entry (int)
        """
        self.parameters['format'] = self.formats[id]
        
        if id == 1:
            self.colourGroupBox.setEnabled(1)
            self.htmlGroupBox.setEnabled(1)
        else:
            self.colourGroupBox.setEnabled(0)
            self.htmlGroupBox.setEnabled(0)
            
        if id in [0, 1]:
            self.datetimeStampCheckBox.setEnabled(1)
        else:
            self.datetimeStampCheckBox.setEnabled(0)
            
        if id in [0, 1, 3]:
            self.prefixLabel.setEnabled(1)
            self.prefixEdit.setEnabled(1)
        else:
            self.prefixLabel.setEnabled(0)
            self.prefixEdit.setEnabled(0)

    def handlePageBackground(self):
        """
        Private method used to select the page background colour.

        It opens a KQColorDialog to select a colour and
        sets the background of the sample textedit.
        """
        self.parameters['pageBackgroundColor'] = self.selectBgColour(self.pbEdit,
            self.parameters['pageBackgroundColor'])

    def handleCodeForeground(self):
        """
        Private method used to select the page foreground colour.

        It opens a KQColorDialog to select a colour and
        sets the background of the sample textedit.
        """
        self.parameters['codeForegroundColor'] = self.selectFgColour(self.cfEdit,
            self.parameters['codeForegroundColor'])

    def handleL1HeadingBackground(self):
        """
        Private method used to select the level 1 heading background colour.

        It opens a KQColorDialog to select a colour and
        sets the background of the sample textedit.
        """
        self.parameters['levelOneHeadingBackgroundColor'] = self.selectBgColour(self.l1hEdit,
            self.parameters['levelOneHeadingBackgroundColor'])

    def handleL1HeadingForeground(self):
        """
        Private method used to select the level 1 heading foreground colour.

        It opens a KQColorDialog to select a colour and
        sets the background of the sample textedit.
        """
        self.parameters['levelOneHeadingForegroundColor'] = self.selectFgColour(self.l1hEdit,
            self.parameters['levelOneHeadingForegroundColor'])

    def handleL2HeadingBackground(self):
        """
        Private method used to select the level 2 heading background colour.

        It opens a KQColorDialog to select a colour and
        sets the background of the sample textedit.
        """
        self.parameters['levelTwoHeadingBackgroundColor'] = self.selectBgColour(self.l2hEdit,
            self.parameters['levelTwoHeadingBackgroundColor'])

    def handleL2HeadingForeground(self):
        """
        Private method used to select the level 2 heading foreground colour.

        It opens a KQColorDialog to select a colour and
        sets the background of the sample textedit.
        """
        self.parameters['levelTwoHeadingForegroundColor'] = self.selectFgColour(self.l2hEdit,
            self.parameters['levelTwoHeadingForegroundColor'])

    def handleDocsetSelected(self, id):
        """
        Private slot to handle the QButtonGroups clicked(int) signal.
        
        It sets the selected docset type.
        
        @param id id of the selected entry (int)
        """
        self.parameters['docset_type'] = self.docsets[id]

    def handleDocstringSyntaxSelected(self, id):
        """
        Private slot to handle the QButtonGroups clicked(int) signal.
        
        It sets the selected docstring syntax.
        
        @param id id of the selected entry (int)
        """
        self.parameters['docStringFormat'] = self.syntaxes[id]

    def handlePackageDescrFile(self):
        """
        Private slot to select the package description file.
        
        It displays a file selection dialog to
        select the package description file.
        """
        file = KQFileDialog.getOpenFileName(self.packageDescrFileEdit.text(),
            None, self, None, self.trUtf8("Select package description file"))
            
        if not file.isNull():
            self.packageDescrFileEdit.setText(QDir.convertSeparators(file))
        
    def handleOutputDir(self):
        """
        Private slot to select the output directory.
        
        It displays a directory selection dialog to
        select the directory the documentations is written to.
        """
        directory = KQFileDialog.getExistingDirectory(self.outputDirEdit.text(),
            self, None, self.trUtf8("Select output directory"))
            
        if not directory.isNull():
            # make it relative, if it is a subdirectory of the project path 
            dn = unicode(QDir.convertSeparators(directory))
            dn = dn.replace(self.ppath+os.sep, '')
            while dn.endswith(os.sep):
                dn = dn[:-1]
            self.outputDirEdit.setText(dn)

    def handleIgnoreDir(self):
        """
        Private slot to select a directory to be ignored.
        
        It displays a directory selection dialog to
        select a directory to be ignored.
        """
        directory = KQFileDialog.getExistingDirectory(self.ignoreDirEdit.text(),
            self, None, self.trUtf8("Select directory to ignore"), 1, 0)
            
        if not directory.isNull():
            # make it relative, if it is a subdirectory of the project path 
            dn = str(QDir.convertSeparators(directory))
            dn = dn.replace(self.ppath+os.sep, '')
            while dn.endswith(os.sep):
                dn = dn[:-1]
            self.ignoreDirEdit.setText(dn)

    def handleIgnoreDirAdd(self):
        """
        Private slot to add the directory displayed to the listview.
        
        The directory in the ignore directories
        line edit is moved to the listbox above and the edit is cleared.
        """
        self.ignoreDirsListBox.insertItem(QDir.convertSeparators(self.ignoreDirEdit.text()))
        self.ignoreDirEdit.clear()

    def handleIgnoreDirDelete(self):
        """
        Private slot to delete the currently selected directory of the listbox.
        """
        self.ignoreDirsListBox.removeItem(self.ignoreDirsListBox.currentItem())

    def accept(self):
        """
        Protected slot called by the Ok button. 
        
        It saves the values in the parameters dictionary.
        """
        # parameters of formatter tab
        self.parameters['compactHTML'] = self.compactHTMLCheckBox.isChecked()
        self.parameters['htmlQuoteText'] = self.quoteHTMLCheckBox.isChecked()
        self.parameters['dateStampFiles'] = self.datetimeStampCheckBox.isChecked()
        self.parameters['filenamePrefix'] = str(self.prefixEdit.text())
        
        # parameters of docset tab
        self.parameters['includeComments'] = self.commentsCheckBox.isChecked()
        self.parameters['includePrivateNames'] = self.privateCheckBox.isChecked()
        self.parameters['usePackages'] = self.packagesCheckBox.isChecked()
        self.parameters['useRecursion'] = self.recursionCheckBox.isChecked()
        self.parameters['prewrittenFileBasenames'] = str(self.prewrittenEdit.text())
        self.parameters['title'] = str(self.titleEdit.text())
        
        # parameters of various tab
        self.parameters['author'] = str(self.authorEdit.text())
        pdFile = str(self.packageDescrFileEdit.text())
        if pdFile == '':
            self.parameters['packageDescriptionFile'] = ''
        else:
            self.parameters['packageDescriptionFile'] = \
                Utilities.normcasepath(pdFile)
        outdir = str(self.outputDirEdit.text())
        if outdir != '':
            outdir = Utilities.normcasepath(outdir)
            if outdir.endswith(os.sep):
                outdir = outdir[:-1]
        self.parameters['outputDirectory'] = outdir
        itm = self.ignoreDirsListBox.firstItem()
        self.parameters['ignoreDirectories'] = []
        while itm is not None:
            self.parameters['ignoreDirectories'].append(\
                Utilities.normcasepath(str(itm.text())))
            itm = itm.next()
        
        # call the accept slot of the base class
        HappydocConfigForm.accept(self)
