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

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

"""
Module implementing the search and replace dialog.
"""

from qt import *

from KdeQt import KQMessageBox

from SearchReplaceForm import SearchReplaceForm

from UI.E3Action import E3Action

class SearchReplaceDialog(SearchReplaceForm):
    """
    Class implementing the search and replace dialog.
    """
    def __init__(self,replace,vm,parent = None,name = None,modal = 0,fl = 0):
        """
        Constructor
        
        @param replace flag indicating a replace dialog is called
        @param vm reference to the viewmanager object
        @param parent parent widget of this dialog (QWidget)
        @param name name of this dialog (string or QString)
        @param modal flag indicating a modal dialog
        @param fl window flags
        """
        SearchReplaceForm.__init__(self,parent,name,modal,fl)
        
        self.viewmanager = vm
        
        self.findHistory = vm.getSRHistory('search')
        if replace:
            self.replaceHistory = vm.getSRHistory('replace')
            self.setCaption(self.trUtf8("Find and Replace"))
            self.replace = 1
        else:
            self.wrapCheckBox.setChecked(1)
            self.replaceTextLabel.hide()
            self.replacetextCombo.hide()
            self.replaceButton.hide()
            self.replaceAllButton.hide()
            self.setCaption(self.trUtf8("Find"))
            self.replace = 0
            
        self.findNextAct = E3Action(self.trUtf8('Find Next'),
                self.trUtf8('Find Next'),
                0,0,self,'search_dialog_find_next')
        self.findNextAct.connectIt(SIGNAL('activated()'),self.handleFindNext)
        self.findNextAct.setEnabled(0)
        
        self.resize(self.width(), 1)
            
        self.havefound = 0

    def enableFindButtons(self):
        """
        Private slot to enable/disable the find buttons.
        """
        if self.findtextCombo.currentText().isEmpty():
            self.findButton.setEnabled(0)
            self.findNextButton.setEnabled(0)
            self.replaceButton.setEnabled(0)
            self.replaceAllButton.setEnabled(0)
            self.findNextAct.setEnabled(0)
        else:
            self.findButton.setEnabled(1)
            self.findNextButton.setEnabled(1)
            self.findNextAct.setEnabled(1)
            if self.replace:
                self.replaceButton.setEnabled(0)
                self.replaceAllButton.setEnabled(1)

    def handleFind(self, searchText = QString.null):
        """
        Private slot to find the entered text in the displayed editor.
        
        @param searchText text to be searched for (QString)
        """
        if not searchText.isEmpty():
            self.findtextCombo.setCurrentText(searchText)
            self.havefound = 1
        txt = self.findtextCombo.currentText()
        
        # This moves any previous occurence of this statement to the head
        # of the list and updates the combobox
        self.findHistory.remove(txt)
        self.findHistory.prepend(txt)
        self.findtextCombo.clear()
        self.findtextCombo.insertStringList(self.findHistory)
        self.emit(PYSIGNAL('searchListChanged'), ())
        
        aw = self.viewmanager.activeWindow()
        cline, cindex = aw.getCursorPosition()
        
        if self.limitCheckBox.isChecked():
            if self.backwardsCheckBox.isChecked():
                line = min(self.endLineSpinBox.value(), aw.lines()) - 1
                index = aw.lineLength(line)
            else:
                line = self.startLineSpinBox.value() - 1
                index = 0
        else:
            line = 0
            index = 0
            
        ok = aw.findFirst(txt,
                self.regexpCheckBox.isChecked(),
                self.caseCheckBox.isChecked(),
                self.wordCheckBox.isChecked(),
                self.wrapCheckBox.isChecked(),
                not self.backwardsCheckBox.isChecked(),
                line, index)
        
        if ok and self.limitCheckBox.isChecked():
            lineFrom, indexFrom, lineTo, indexTo = aw.getSelection()
            if lineFrom >= (self.startLineSpinBox.value() - 1) and \
               lineFrom <= min(self.endLineSpinBox.value(), aw.lines()) - 1:
                ok = 1
            else:
                ok = 0
                aw.selectAll(0)
                aw.setCursorPosition(cline, cindex)
                aw.ensureCursorVisible()
        if ok:
            self.replaceButton.setEnabled(1)
        else:
            KQMessageBox.information(self, self.caption(),
                self.trUtf8("'%1' was not found.").arg(txt))

    def handleFindNext(self):
        """
        Public slot to find the next occurance of text.
        """
        if not self.havefound or self.findtextCombo.currentText().isEmpty():
            self.showFind(self.viewmanager.textForFind())
            return
        
        txt = self.findtextCombo.currentText()
        
        # This moves any previous occurence of this statement to the head
        # of the list and updates the combobox
        self.findHistory.remove(txt)
        self.findHistory.prepend(txt)
        self.findtextCombo.clear()
        self.findtextCombo.insertStringList(self.findHistory)
        self.emit(PYSIGNAL('searchListChanged'), ())
        
        ok = self.findNext(txt)
        if ok:
            self.replaceButton.setEnabled(1)
        else:
            KQMessageBox.information(self, self.caption(),
                self.trUtf8("'%1' was not found.").arg(txt))

    def findNext(self, txt):
        """
        Private method to find the next occurance of the search text.
        
        @param txt text to search for (QString)
        @return flag indicating success (boolean)
        """
        aw = self.viewmanager.activeWindow()
        cline, cindex = aw.getCursorPosition()
        
        ok = 1
        lineFrom, indexFrom, lineTo, indexTo = aw.getSelection()
        if self.backwardsCheckBox.isChecked():
            line = lineFrom
            index = indexFrom - 1
            if index < 0:
                line -= 1
                if self.limitCheckBox.isChecked():
                    if line < self.startLineSpinBox.value() - 1:
                        if self.wrapCheckBox.isChecked():
                            line = min(self.endLineSpinBox.value(), aw.lines()) - 1
                        else:
                            ok = 0
                else:
                    if line < 0:
                        if self.wrapCheckBox.isChecked():
                            line = aw.lines()-1
                        else:
                            ok = 0
                if ok:
                    index = aw.lineLength(line)
        else:
            line = lineTo
            index = indexTo
            
        if ok:
            ok = aw.findFirst(txt,
                self.regexpCheckBox.isChecked(),
                self.caseCheckBox.isChecked(),
                self.wordCheckBox.isChecked(),
                self.wrapCheckBox.isChecked(),
                not self.backwardsCheckBox.isChecked(),
                line, index)
        
        if ok and self.limitCheckBox.isChecked():
            lineFrom, indexFrom, lineTo, indexTo = aw.getSelection()
            if lineFrom >= (self.startLineSpinBox.value() - 1) and \
               lineFrom <= min(self.endLineSpinBox.value(), aw.lines()) - 1:
                ok = 1
            else:
                if self.wrapCheckBox.isChecked():
                    # try it again
                    if self.backwardsCheckBox.isChecked():
                        line = min(self.endLineSpinBox.value(), aw.lines()) - 1
                        index = aw.lineLength(line)
                    else:
                        line = self.startLineSpinBox.value() - 1
                        index = 0
                    ok = aw.findFirst(txt,
                        self.regexpCheckBox.isChecked(),
                        self.caseCheckBox.isChecked(),
                        self.wordCheckBox.isChecked(),
                        self.wrapCheckBox.isChecked(),
                        not self.backwardsCheckBox.isChecked(),
                        line, index)
                    if ok:
                        lineFrom, indexFrom, lineTo, indexTo = aw.getSelection()
                        if lineFrom >= (self.startLineSpinBox.value() - 1) and \
                           lineFrom <= min(self.endLineSpinBox.value(), aw.lines()) - 1:
                            ok = 1
                        else:
                            ok = 0
                            aw.selectAll(0)
                            aw.setCursorPosition(cline, cindex)
                            aw.ensureCursorVisible()
                else:
                    ok = 0
                    aw.selectAll(0)
                    aw.setCursorPosition(cline, cindex)
                    aw.ensureCursorVisible()
        return ok

    def showFind(self, text=''):
        """
        Public method to display this dialog in find mode.
        
        @param text text to be shown in the findtext edit
        """
        self.replace = 0
        
        self.findtextCombo.clear()
        self.findtextCombo.insertStringList(self.findHistory)
        self.findtextCombo.setCurrentText(text)
        self.findtextCombo.lineEdit().selectAll()
        self.findtextCombo.setFocus()
        
        self.caseCheckBox.setChecked(0)
        self.wordCheckBox.setChecked(0)
        self.backwardsCheckBox.setChecked(0)
        self.wrapCheckBox.setChecked(1)
        self.regexpCheckBox.setChecked(0)
        
        aw = self.viewmanager.activeWindow()
        if aw.hasSelectedText():
            line1, dummy1, line2, dummy2 = aw.getSelection()
            self.startLineSpinBox.setValue(line1 + 1)
            self.endLineSpinBox.setValue(line2 + 1)
        else:
            self.endLineSpinBox.setValue(aw.lines())
        
        self.findNextAct.setAccel(self.viewmanager.searchAgainAct.accel())
        self.findNextAct.setAlternateAccel(self.viewmanager.searchAgainAct.alternateAccel())
        
        self.havefound = 1
        self.show()

    def handleReplace(self):
        """
        Public slot to replace one occurance of text.
        """
        ftxt = self.findtextCombo.currentText()
        rtxt = self.replacetextCombo.currentText()
        
        # This moves any previous occurence of this statement to the head
        # of the list and updates the combobox
        self.replaceHistory.remove(rtxt)
        self.replaceHistory.prepend(rtxt)
        self.replacetextCombo.clear()
        self.replacetextCombo.insertStringList(self.replaceHistory)
        
        aw = self.viewmanager.activeWindow()
        aw.replace(rtxt)
        ok = self.findNext(ftxt)
        
        if not ok:
            KQMessageBox.information(self, self.caption(),
                self.trUtf8("'%1' was not found.").arg(ftxt))
        
    def handleReplaceAll(self):
        """
        Public slot to replace all occurances of text.
        """
        ftxt = self.findtextCombo.currentText()
        rtxt = self.replacetextCombo.currentText()
        
        # This moves any previous occurence of this statement to the head
        # of the list and updates the combobox
        self.findHistory.remove(ftxt)
        self.findHistory.prepend(ftxt)
        self.findtextCombo.clear()
        self.findtextCombo.insertStringList(self.findHistory)
        
        self.replaceHistory.remove(rtxt)
        self.replaceHistory.prepend(rtxt)
        self.replacetextCombo.clear()
        self.replacetextCombo.insertStringList(self.replaceHistory)
        
        aw = self.viewmanager.activeWindow()
        cline, cindex = aw.getCursorPosition()
        if self.wrapCheckBox.isChecked():
            if self.limitCheckBox.isChecked():
                line = self.startLineSpinBox.value() - 1
                index = 0
            else:
                line = 0
                index = 0
            ok = aw.findFirst(ftxt,
                    self.regexpCheckBox.isChecked(),
                    self.caseCheckBox.isChecked(),
                    self.wordCheckBox.isChecked(),
                    0, 1, line, index)
        else:
            ok = aw.findFirst(ftxt,
                    self.regexpCheckBox.isChecked(),
                    self.caseCheckBox.isChecked(),
                    self.wordCheckBox.isChecked(),
                    0,
                    not self.backwardsCheckBox.isChecked())
            
        if ok and self.limitCheckBox.isChecked():
            lineFrom, indexFrom, lineTo, indexTo = aw.getSelection()
            if lineFrom >= (self.startLineSpinBox.value() - 1) and \
               lineFrom <= min(self.endLineSpinBox.value(), aw.lines()) - 1:
                ok = 1
            else:
                ok = 0
                aw.selectAll(0)
            
        found = ok
        
        wordWrap = self.wrapCheckBox.isChecked()
        self.wrapCheckBox.setChecked(0)
        aw.beginUndoAction()
        while ok:
            aw.replace(rtxt)
            ok = self.findNext(ftxt)
        aw.endUndoAction()
        if wordWrap:
            self.wrapCheckBox.setChecked(1)
        aw.setCursorPosition(cline, cindex)
        aw.ensureCursorVisible()
        
        if not found:
            KQMessageBox.information(self, self.caption(),
                self.trUtf8("Nothing replaced because '%1' was not found.")
                    .arg(ftxt))
        
    def showReplace(self, text=''):
        """
        Public slot to display this dialog in replace mode.
        
        @param text text to be shown in the findtext edit
        """
        self.replace = 1
        
        self.findtextCombo.clear()
        self.findtextCombo.insertStringList(self.findHistory)
        self.findtextCombo.setCurrentText(text)
        self.findtextCombo.lineEdit().selectAll()
        self.findtextCombo.setFocus()
        
        self.replacetextCombo.clear()
        self.replacetextCombo.insertStringList(self.replaceHistory)
        self.replacetextCombo.setCurrentText('')
        
        self.caseCheckBox.setChecked(0)
        self.wordCheckBox.setChecked(0)
        self.backwardsCheckBox.setChecked(0)
        self.wrapCheckBox.setChecked(1)
        self.regexpCheckBox.setChecked(0)
        
        aw = self.viewmanager.activeWindow()
        if aw.hasSelectedText():
            line1, dummy1, line2, dummy2 = aw.getSelection()
            self.startLineSpinBox.setValue(line1 + 1)
            self.endLineSpinBox.setValue(line2 + 1)
        else:
            self.endLineSpinBox.setValue(aw.lines())
        
        self.findNextAct.setAccel(self.viewmanager.searchAgainAct.accel())
        self.findNextAct.setAlternateAccel(self.viewmanager.searchAgainAct.alternateAccel())
        
        self.havefound = 1
        self.show()
