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

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

"""
Module implementing a dialog for entering character classes.
"""

from qt import *
from QRegExpWizardCharactersForm import QRegExpWizardCharactersForm


class QRegExpWizardCharactersDialog(QRegExpWizardCharactersForm):
    """
    Module implementing a dialog for entering character classes.
    """
    specialChars = {
        4 : "\\a",
        5 : "\\f",
        6 : "\\n",
        7 : "\\r",
        8 : "\\t",
        9 : "\\v"
    }
    
    predefinedClasses = ["\\s", "\\S", "\\w", "\\W", "\\d", "\\D"]
    
    def __init__(self,parent = None):
        """
        Constructor
        
        @param parent parent widget (QWidget)
        """
        QRegExpWizardCharactersForm.__init__(self,parent)
        
        self.comboItems = QStringList()
        self.comboItems.append(self.trUtf8("Normal character"))
        self.comboItems.append(self.trUtf8("Unicode character in hexadecimal notation"))
        self.comboItems.append(self.trUtf8("Unicode character in octal notation"))
        self.comboItems.append(self.trUtf8("---"))
        self.comboItems.append(self.trUtf8("Bell character (\\a)"))
        self.comboItems.append(self.trUtf8("Page break (\\f)"))
        self.comboItems.append(self.trUtf8("Line feed (\\n)"))
        self.comboItems.append(self.trUtf8("Carriage return (\\r)"))
        self.comboItems.append(self.trUtf8("Horizontal tabulator (\\t)"))
        self.comboItems.append(self.trUtf8("Vertical tabulator (\\v)"))
        
        self.charValidator = QRegExpValidator(QRegExp(".{0,1}"), self)
        self.hexValidator = QRegExpValidator(QRegExp("[0-9a-fA-F]{0,4}"), self)
        self.octValidator = QRegExpValidator(QRegExp("[0-3]?[0-7]{0,2}"), self)
        
        # generate dialog part for single characters
        self.singlesBox.setColumnLayout(0,Qt.Vertical)
        self.singlesBox.layout().setSpacing(6)
        self.singlesBox.layout().setMargin(6)
        singlesBoxLayout = QVBoxLayout(self.singlesBox.layout())
        self.singlesView = QScrollView(self.singlesBox, "singlesView")
        singlesBoxLayout.addWidget(self.singlesView)
        
        self.singlesItemsBox = QVBox(self.singlesView.viewport(), "singlesItemsBox")
        self.singlesItemsBox.setMargin(6)
        self.singlesItemsBox.setSpacing(6)
        self.singlesEntries = []
        self.addSinglesLine()
        
        hlayout0 = QHBoxLayout(self.singlesBox, 0, 6, "hlayout0")
        self.moreSinglesButton = QPushButton(self.trUtf8("Additional Entries"),
            self.singlesBox, "moreSinglesButton")
        hlayout0.addWidget(self.moreSinglesButton)
        hspacer0 = QSpacerItem(30,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
        hlayout0.addItem(hspacer0)
        singlesBoxLayout.addLayout(hlayout0)
        self.connect(self.moreSinglesButton, SIGNAL("clicked()"), self.addSinglesLine)
        
        # generate dialog part for character ranges
        self.rangesBox.setColumnLayout(0,Qt.Vertical)
        self.rangesBox.layout().setSpacing(6)
        self.rangesBox.layout().setMargin(6)
        rangesBoxLayout = QVBoxLayout(self.rangesBox.layout())
        self.rangesView = QScrollView(self.rangesBox, "rangesView")
        rangesBoxLayout.addWidget(self.rangesView)
        
        self.rangesItemsBox = QVBox(self.rangesView.viewport(), "rangesItemBox")
        self.rangesItemsBox.setMargin(6)
        self.rangesItemsBox.setSpacing(6)
        self.rangesEntries = []
        self.addRangesLine()
        
        hlayout1 = QHBoxLayout(self.rangesBox, 0, 6, "hlayout1")
        self.moreRangesButton = QPushButton(self.trUtf8("Additional Entries"),
            self.rangesBox, "moreRangesButton")
        hlayout1.addWidget(self.moreRangesButton)
        hspacer1 = QSpacerItem(30,20,QSizePolicy.Expanding,QSizePolicy.Minimum)
        hlayout1.addItem(hspacer1)
        rangesBoxLayout.addLayout(hlayout1)
        self.connect(self.moreRangesButton, SIGNAL("clicked()"), self.addRangesLine)
        
    def addSinglesLine(self):
        """
        Private slot to add a line of entry widgets for single characters.
        """
        hbox = QHBox(self.singlesItemsBox)
        hbox.setMargin(0)
        hbox.setSpacing(6)
        cb1 = QComboBox(0, hbox)
        cb1.insertStringList(self.comboItems)
        le1 = QLineEdit(hbox)
        le1.setValidator(self.charValidator)
        cb2 = QComboBox(0, hbox)
        cb2.insertStringList(self.comboItems)
        le2 = QLineEdit(hbox)
        le2.setValidator(self.charValidator)
        
        self.connect(cb1, SIGNAL('activated(int)'), self.handleSinglesCharTypeSelected)
        self.connect(cb2, SIGNAL('activated(int)'), self.handleSinglesCharTypeSelected)
        hbox.show()
        
        self.singlesItemsBox.adjustSize()
        self.singlesView.resizeContents(self.singlesItemsBox.width(),
            self.singlesItemsBox.height())
        
        self.singlesEntries.append([cb1, le1])
        self.singlesEntries.append([cb2, le2])
        
    def addRangesLine(self):
        """
        Private slot to add a line of entry widgets for character ranges.
        """
        hbox = QHBox(self.rangesItemsBox)
        hbox.setMargin(0)
        hbox.setSpacing(6)
        l1 = QLabel(self.trUtf8("Between:"), hbox)
        cb1 = QComboBox(0, hbox)
        cb1.insertStringList(self.comboItems)
        le1 = QLineEdit(hbox)
        le1.setValidator(self.charValidator)
        l2 = QLabel(self.trUtf8("And:"), hbox)
        cb2 = QComboBox(0, hbox)
        cb2.insertStringList(self.comboItems)
        le2 = QLineEdit(hbox)
        le2.setValidator(self.charValidator)
        
        self.connect(cb1, SIGNAL('activated(int)'), self.handleRangesCharTypeSelected)
        self.connect(cb2, SIGNAL('activated(int)'), self.handleRangesCharTypeSelected)
        hbox.show()
        
        self.rangesItemsBox.adjustSize()
        self.rangesView.resizeContents(self.rangesItemsBox.width(),
            self.rangesItemsBox.height())
        
        self.rangesEntries.append([cb1, le1, cb2, le2])
        
    def performSelectedAction(self, index, lineedit):
        """
        Private method performing some actions depending on the input.
        
        @param index selected list index (integer)
        @param lineedit line edit widget to act on (QLineEdit)
        """
        if index < 3:
            lineedit.setEnabled(1)
            if index == 0:
                lineedit.setValidator(self.charValidator)
            elif index == 1:
                lineedit.setValidator(self.hexValidator)
            elif index == 2:
                lineedit.setValidator(self.octValidator)
        elif index > 3:
            lineedit.setEnabled(0)
        lineedit.clear()
        
    def handleSinglesCharTypeSelected(self, index):
        """
        Private slot to handle the activated(int) signal of the single chars combo boxes.
        
        @param index selected list index (integer)
        """
        combo = self.sender()
        for entriesList in self.singlesEntries:
            if combo == entriesList[0]:
                self.performSelectedAction(index, entriesList[1])
        
    def handleRangesCharTypeSelected(self, index):
        """
        Private slot to handle the activated(int) signal of the char ranges combo boxes.
        
        @param index selected list index (integer)
        """
        combo = self.sender()
        for entriesList in self.rangesEntries:
            if combo == entriesList[0]:
                self.performSelectedAction(index, entriesList[1])
            elif combo == entriesList[2]:
                self.performSelectedAction(index, entriesList[3])
        
    def formatCharacter(self, index, char):
        """
        Private method to format the characters entered into the dialog.
        
        @param index selected list index (integer)
        @param char character string enetered into the dialog (string)
        @return formated character string (string)
        """
        if index == 0:
            return char
        elif index == 1:
            return "\\x%s" % char.lower()
        elif index == 2:
            return "\\0%s" % char
        else:
            try:
                return self.specialChars[index]
            except KeyError:
                return ""
        
    def getCharacters(self):
        """
        Public method to return the character string assembled via the dialog.
        
        @return formatted string for character classes (string)
        """
        regexp = ""
        
        # negative character range
        if self.negativeCheckBox.isChecked():
            regexp += "^"
            
        # predefined character ranges
        if self.wordCharCheckBox.isChecked():
            regexp += "\\w"
        if self.nonWordCharCheckBox.isChecked():
            regexp += "\\W"
        if self.digitsCheckBox.isChecked():
            regexp += "\\d"
        if self.nonDigitsCheckBox.isChecked():
            regexp += "\\D"
        if self.whitespaceCheckBox.isChecked():
            regexp += "\\s"
        if self.nonWhitespaceCheckBox.isChecked():
            regexp += "\\S"
            
        # single characters
        for entrieslist in self.singlesEntries:
            index = entrieslist[0].currentItem()
            char = unicode(entrieslist[1].text())
            regexp += self.formatCharacter(index, char)
        
        # character ranges
        for entrieslist in self.rangesEntries:
            if entrieslist[1].text().isEmpty() or \
               entrieslist[3].text().isEmpty():
                continue
            index = entrieslist[0].currentItem()
            char = unicode(entrieslist[1].text())
            regexp += "%s-" % self.formatCharacter(index, char)
            index = entrieslist[2].currentItem()
            char = unicode(entrieslist[3].text())
            regexp += self.formatCharacter(index, char)
        
        if regexp:
            if len(regexp) == 2 and regexp in self.predefinedClasses:
                return regexp
            else:
                return "[%s]" % regexp
        else:
            return ""
