from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt

import re

class Find(QtGui.QDialog):
    def __init__(self, parent = None):
        
        QtGui.QDialog.__init__(self, parent)

        self.parent = parent

        self.lastStart = 0

        self.initUI()
 
    def initUI(self):

        # Button to search the document for something
        findButton = QtGui.QPushButton("Find",self)
        findButton.clicked.connect(self.find)

        # Button to replace the last finding
        replaceButton = QtGui.QPushButton("Replace",self)
        replaceButton.clicked.connect(self.replace)

        # Button to remove all findings
        allButton = QtGui.QPushButton("Replace all",self)
        allButton.clicked.connect(self.replaceAll)

        # Normal mode - radio button
        self.normalRadio = QtGui.QRadioButton("Normal",self)

        # Regular Expression Mode - radio button
        regexRadio = QtGui.QRadioButton("RegEx",self)

        # The field into which to type the query
        self.findField = QtGui.QTextEdit(self)
        self.findField.resize(250,50)

        # The field into which to type the text to replace the
        # queried text
        self.replaceField = QtGui.QTextEdit(self)
        self.replaceField.resize(250,50)
        
        layout = QtGui.QGridLayout()

        layout.addWidget(self.findField,1,0,1,4)
        layout.addWidget(self.normalRadio,2,2)
        layout.addWidget(regexRadio,2,3)
        layout.addWidget(findButton,2,0,1,2)
        
        layout.addWidget(self.replaceField,3,0,1,4)
        layout.addWidget(replaceButton,4,0,1,2)
        layout.addWidget(allButton,4,2,1,2)

        self.setGeometry(300,300,360,250)
        self.setWindowTitle("Find and Replace")
        self.setLayout(layout)

        # By default the normal mode is activated
        self.normalRadio.setChecked(True)

    def find(self):

        # Grab the parent's text
        text = self.parent.text.toPlainText()

        # And the text to find
        query = self.findField.toPlainText()

        if self.normalRadio.isChecked():

            # Use normal string search to find the query from the
            # last starting position
            self.lastStart = text.find(query,self.lastStart + 1)

            # If the find() method didn't return -1 (not found)
            if self.lastStart >= 0:

                end = self.lastStart + len(query)
                
                self.moveCursor(self.lastStart,end)

            else:

                self.notFound()

        else:

            # Compile the pattern
            pattern = re.compile(query)

            # The actual search
            match = pattern.search(text,self.lastStart + 1)

            if match:

                self.lastStart = match.start()
                
                self.moveCursor(self.lastStart,match.end())

            else:

                self.notFound()

    def replace(self):

        # Grab the text cursor
        cursor = self.parent.text.textCursor()

        # Security
        if cursor.hasSelection():

            # We insert the new text, which will override the selected
            # text
            cursor.insertText(self.replaceField.toPlainText())

            # And set the new cursor
            self.parent.text.setTextCursor(cursor)

    def replaceAll(self):

        self.lastStart = 0

        self.find()

        # Replace and find until self.lastStart is 0 again
        while self.lastStart:
            self.replace()
            self.find()

    def moveCursor(self,start,end):

        # We retrieve the QTextCursor object from the parent's QTextEdit
        cursor = self.parent.text.textCursor()

        # Then we set the position to the beginning of the last match
        cursor.setPosition(start)

        # Next we move the cursor over the match and pass the KeepAnchor parameter
        # which will make the cursor select the the match's text
        cursor.movePosition(QtGui.QTextCursor.Right,QtGui.QTextCursor.KeepAnchor,end - start)

        # And finally we set this new cursor as the parent's 
        self.parent.text.setTextCursor(cursor)

    def notFound(self):

        self.lastStart = 0
                
        # We set the cursor to the end if the search was unsuccessful
        self.parent.text.moveCursor(QtGui.QTextCursor.End)

        # Make system beep
        self.parent.app.beep()