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

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

"""
Module implementing the QRegExp wizard dialog.
"""

import sys
import os

from qt import *

from KdeQt import KQMessageBox

from QRegExpWizardForm import QRegExpWizardForm

from QRegExpWizardRepeatDialog import QRegExpWizardRepeatDialog
from QRegExpWizardCharactersDialog import QRegExpWizardCharactersDialog

import UI.PixmapCache

class QRegExpWizardDialog(QRegExpWizardForm):
    """
    Class implementing the QRegExp wizard dialog.
    """
    def __init__(self,parent = None,fromEric = 1):
        """
        Constructor
        
        @param parent parent widget (QWidget)
        @param fromEric flag indicating a call from within eric3
        """
        QRegExpWizardForm.__init__(self,parent,None,fromEric)
        
        # initialize icons of the tool buttons
        self.charButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("characters.png")))
        self.anycharButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("anychar.png")))
        self.repeatButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("repeat.png")))
        self.groupButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("group.png")))
        self.altnButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("altn.png")))
        self.beglineButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("begline.png")))
        self.endlineButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("endline.png")))
        self.wordboundButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("wordboundary.png")))
        self.nonwordboundButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("nonwordboundary.png")))
        self.poslookaheadButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("poslookahead.png")))
        self.neglookaheadButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("neglookahead.png")))
        self.undoButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("editUndo.png")))
        self.redoButton.setIconSet(\
            QIconSet(UI.PixmapCache.getPixmap("editRedo.png")))
        
        self.resultTable.verticalHeader().hide()
        self.resultTable.setLeftMargin(0)
        self.resultTable.horizontalHeader().hide()
        self.resultTable.setTopMargin(0)
        
        if fromEric:
            self.copyButton.hide()
        else:
            self.variableLabel.hide()
            self.variableLineEdit.hide()
            self.variableLine.hide()
            self.cancelButton.hide()
            self.okButton.setText(self.trUtf8("&Quit"))
        
        mw = qApp.mainWidget()
        if mw:
            uitype = mw.getProject().getUiType()
            if uitype == "Qt4":
                self.rQt4.setChecked(True)

    def insertString(self, s, steps=0):
        """
        Private method to insert a string into line edit and move cursor.
        
        @param s string to be inserted into the regexp line edit
            (string or QString)
        @param steps number of characters to move the cursor (integer).
            Negative steps moves cursor back, positives forward.
        """
        self.regexpLineEdit.insert(s)
        self.regexpLineEdit.cursorForward(0, steps)
        
    def handleAnyChar(self):
        """
        Private slot to handle the any character toolbutton.
        """
        self.insertString(".")
        
    def handleGroup(self):
        """
        Private slot to handle the group toolbutton.
        """
        self.insertString("()", -1)
        
    def handleAlternatives(self):
        """
        Private slot to handle the alternatives toolbutton.
        """
        self.insertString("(|)", -2)
        
    def handleBeginLine(self):
        """
        Private slot to handle the begin line toolbutton.
        """
        self.insertString("^")
        
    def handleEndLine(self):
        """
        Private slot to handle the end line toolbutton.
        """
        self.insertString("$")
        
    def handleWordBoundary(self):
        """
        Private slot to handle the word boundary toolbutton.
        """
        self.insertString("\\b")
        
    def handleNonWordBoundary(self):
        """
        Private slot to handle the non word boundary toolbutton.
        """
        self.insertString("\\B")
        
    def handlePosLookahead(self):
        """
        Private slot to handle the positive lookahead toolbutton.
        """
        self.insertString("(?=)", -1)
        
    def handleNegLookahead(self):
        """
        Private slot to handle the negative lookahead toolbutton.
        """
        self.insertString("(?!)", -1)
        
    def handleRepeat(self):
        """
        Private slot to handle the repeat toolbutton.
        """
        dlg = QRegExpWizardRepeatDialog(self)
        if dlg.exec_loop() == QDialog.Accepted:
            self.insertString(dlg.getRepeat())
        
    def handleCharacters(self):
        """
        Private slot to handle the characters toolbutton.
        """
        dlg = QRegExpWizardCharactersDialog(self)
        if dlg.exec_loop() == QDialog.Accepted:
            self.insertString(dlg.getCharacters())
    
    def copy(self):
        """
        Private slot to copy the regexp string into the clipboard.
        
        This slot is only available, if not called from within eric3.
        """
        escaped = self.regexpLineEdit.text()
        if not escaped.isEmpty():
            escaped = escaped.replace("\\", "\\\\")
            cb = QApplication.clipboard()
            cb.setText(escaped, QClipboard.Clipboard)
            if cb.supportsSelection():
                cb.setText(escaped, QClipboard.Selection)

    def validate(self):
        """
        Private slot to validate the entered regexp.
        """
        regex = self.regexpLineEdit.text()
        if not regex.isEmpty():
            re = QRegExp(regex)
            re.setCaseSensitive(self.caseSensitiveCheckBox.isChecked())
            re.setMinimal(self.minimalCheckBox.isChecked())
            wildcard = self.wildcardCheckBox.isChecked()
            re.setWildcard(wildcard)
            if re.isValid():
                KQMessageBox.information(None,
                    self.trUtf8(""),
                    self.trUtf8("""The regular expression is valid."""),
                    self.trUtf8("&OK"),
                    QString.null,
                    QString.null,
                    0, -1)
            else:
                KQMessageBox.critical(None,
                    self.trUtf8("Error"),
                    self.trUtf8("""Invalid regular expression: %1""")
                        .arg(re.errorString()),
                    self.trUtf8("&OK"),
                    QString.null,
                    QString.null,
                    0, -1)
                return
        else:
            KQMessageBox.critical(None,
                self.trUtf8("Error"),
                self.trUtf8("""A regular expression must be given."""),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)

    def execute(self):
        """
        Private slot to execute the entered regexp on the test text.
        
        This slot will execute the entered regexp on the entered test
        data and will display the result in the table part of the dialog.
        """
        regex = self.regexpLineEdit.text()
        text = self.textTextEdit.text()
        if not regex.isEmpty() and not text.isEmpty():
            re = QRegExp(regex)
            re.setCaseSensitive(self.caseSensitiveCheckBox.isChecked())
            re.setMinimal(self.minimalCheckBox.isChecked())
            wildcard = self.wildcardCheckBox.isChecked()
            re.setWildcard(wildcard)
            if not re.isValid():
                KQMessageBox.critical(None,
                    self.trUtf8("Error"),
                    self.trUtf8("""Invalid regular expression: %1""")
                        .arg(re.errorString()),
                    self.trUtf8("&OK"),
                    QString.null,
                    QString.null,
                    0, -1)
                return
            offset = re.search(text)
            captures = re.numCaptures()
            row = 0
            OFFSET = 5
            
            self.resultTable.setNumRows(0)
            self.resultTable.setNumRows(captures + OFFSET)
            self.resultTable.setText(row, 0, self.trUtf8("Regexp"))
            self.resultTable.setText(row, 1, regex)
            self.resultTable.item(row, 1).setSpan(1, 2)
            
            if offset != -1:
                row += 1
                self.resultTable.setText(row, 0, self.trUtf8("Offset"))
                self.resultTable.setText(row, 1, QString.number(offset))
                self.resultTable.item(row, 1).setSpan(1, 2)
                
                if not wildcard:
                    row += 1
                    self.resultTable.setText(row, 0, self.trUtf8("Captures"))
                    self.resultTable.setText(row, 1, QString.number(captures))
                    self.resultTable.item(row, 1).setSpan(1, 2)
                    row += 1
                    self.resultTable.setText(row, 1, self.trUtf8("Text"))
                    self.resultTable.setText(row, 2, self.trUtf8("Characters"))
                    
                row += 1
                self.resultTable.setText(row, 0, self.trUtf8("Match"))
                self.resultTable.setText(row, 1, re.cap(0))
                self.resultTable.setText(row, 2, QString.number(re.matchedLength()))
                
                if not wildcard:
                    for i in range(1, captures + 1):
                        self.resultTable.setText(row + i, 0, self.trUtf8("Capture #%1").arg(i))
                        self.resultTable.setText(row + i, 1, re.cap(i))
                        self.resultTable.setText(row + i, 2, QString.number(re.cap(i).length()))
                else:
                    self.resultTable.setNumRows(3)
            else:
                self.resultTable.setNumRows(2)
                row += 1
                self.resultTable.setText(row, 0, self.trUtf8("No matches"))
                self.resultTable.item(row, 0).setSpan(1, 3)
                
            for i in range(self.resultTable.numCols()):
                self.resultTable.adjustColumn(i)
            for i in range(self.resultTable.numRows()):
                self.resultTable.adjustRow(i)
        else:
            KQMessageBox.critical(None,
                self.trUtf8("Error"),
                self.trUtf8("""A regular expression and a text must be given."""),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)
        
    def getCode(self, indLevel, indString):
        """
        Public method to get the source code.
        
        @param indLevel indentation level (int)
        @param indString string used for indentation (space or tab) (string)
        @return generated code (string)
        """
        # calculate the indentation string
        istring = indLevel * indString
        
        # now generate the code
        reVar = unicode(self.variableLineEdit.text())
        if not reVar:
            reVar = "regexp"
            
        regexp = unicode(self.regexpLineEdit.text())
        
        code = '%s = QRegExp(r"""%s""")%s' % \
            (reVar, regexp.replace('"', '\\"'), os.linesep)
        if not self.caseSensitiveCheckBox.isChecked():
            if self.rQt4.isChecked():
                code += '%s%s.setCaseSensitivity(Qt.CaseInsensitive)%s' % \
                        (istring, reVar, os.linesep)
            else:
                code += '%s%s.setCaseSensitive(0)%s' % (istring, reVar, os.linesep)
        if self.minimalCheckBox.isChecked():
            code += '%s%s.setMinimal(1)%s' % (istring, reVar, os.linesep)
        if self.wildcardCheckBox.isChecked():
            if self.rQt4.isChecked():
                code += '%s%s.setPatternSyntax(QRegExp.Wildcard)%s' % \
                        (istring, reVar, os.linesep)
            else:
                code += '%s%s.setWildcard(1)%s' % (istring, reVar, os.linesep)
        return code
