#   Programmer:  Franz Steinhaeusler
#   E-mail:      francescoa@users.sourceforge.net
#   Note:        Initial Release 12/15/2004
#
#   Copyright 2004-2005 Franz Steinhaeusler
#
#   Distributed under the terms of the GPL (GNU Public License)
#
#    DrPython is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#Plugin
#IncrementalSearch

#Version: 0.0.0, 15.12.2004
#Version: 0.0.1, 21.01.2005

import wx
#this is needed for PyChecker
#import sys
#sys.path.append('c:/Eigene Dateien/python/drpython')

def OnAbout(DrFrame):
    IncrementalSearch_Version = "0.0.1"
    NameAndVersion = "IncrementalSearch:\n\nVersion: " + IncrementalSearch_Version + "\n"
    AboutString = NameAndVersion + "By Franz Steinhaeusler\n\nReleased under the GPL."
    DrFrame.ShowMessage(AboutString, "About")

def OnHelp(DrFrame):
    HelpText=\
"\
this pluin is based on scite incremental Search and I took some ideas from multi-edit.\n\n\
You can quit the dialog with:\n\
ESC: jumps back to old cursor position.\n\
Cursor Keys: it performs a curor movement of the current search position.\n\n\
Search next: enter key or alt-n, or button\n\
Search previous: shift-enter key or alt-p\n\n\
the textctrl ignore keys, where no search string is found.\n\
Special handling of backspace key.\n\n\
Enjoy!\n\
"
    DrFrame.ShowMessage(HelpText, "IncrementalSearch")

#def OnPreferences(DrFrame):
#   pass

class IncrementalSearchDlg(wx.Dialog):
    def __init__ (self, parent, xpos, ypos):
        wx.Dialog.__init__ (self, parent, -1, "", (xpos, ypos), (340, 28), style=0)
        wx.StaticText(self, -1, "Incr. Search:", (8, 7))
        self.textctrl = wx.TextCtrl(self, -1, pos = (80, 2), size = (220, 22), style = wx.TE_PROCESS_ENTER)
        self.btnnextfind = wx.Button(self, -1, "->", pos = (310, 2), size = (22,22))
        self.Bind(wx.EVT_BUTTON,  self.OnbtnNextFind, id = -1)
        self.textctrl.Bind(wx.EVT_KEY_DOWN,  self.OnProcessInput, id = -1)
        self.parent = parent
        self.Bind(wx.EVT_TEXT,  self.OnProcessText, id = -1)
        self.bs = False
        self.findpos = self.parent.txtDocument.GetCurrentPos()
        self.dir = 0
        if not self.PLATFORM_IS_WIN: #on gtk, it needs additional setfocus
            self.textctrl.SetFocus()

    def OnbtnNextFind (self, event):
        self.FindNext()
        self.textctrl.SetFocus()
        if event:
            event.Skip()

    def OnProcessText(self, event):
        if not self.bs:
            self.findpos = self.parent.txtDocument.GetSelectionStart()
        oldpos = self.findpos
        self.FindNext()
        #nothing found: cancel last character
        if oldpos == self.findpos:
            self.textctrl.SetValue(self.textctrl.GetValue()[:-1])
            self.textctrl.SetInsertionPoint (len (self.textctrl.GetValue()))
        event.Skip()

    def FindNext(self):
        if self.textctrl.GetValue():
            if self.dir == 2:
                self.findpos += 2
            self.dir = 1
            oldfindpos = self.findpos
            self.findpos = self.parent.txtDocument.FindText(self.findpos, self.parent.txtDocument.GetLength(), self.textctrl.GetValue(), 0)
            if self.findpos == -1:
                self.findpos = oldfindpos
            else:
                if self.parent.prefs.docfolding:
                    self.parent.txtDocument.EnsureVisible(self.parent.txtDocument.LineFromPosition(self.findpos))
                self.parent.txtDocument.EnsureCaretVisible()
                self.parent.txtDocument.GotoPos(self.findpos)
                self.parent.txtDocument.SetSelectionStart(self.findpos)
                self.parent.txtDocument.SetSelectionEnd(self.findpos + len(self.textctrl.GetValue()))

                self.findpos += 1
        else:
            self.parent.txtDocument.SetSelection (self.parent.IncrementalSearch_OldCursorPos, self.parent.IncrementalSearch_OldCursorPos)

    def FindPrevious(self):
        if self.textctrl.GetValue():
            if self.dir == 1:
                self.findpos -= 2
            self.dir = 2
            oldfindpos = self.findpos
            self.findpos = self.parent.txtDocument.FindText(self.findpos, 0, self.textctrl.GetValue(), 0)
            if self.findpos == -1:
                self.findpos = oldfindpos
            else:
                if self.parent.prefs.docfolding:
                    self.parent.txtDocument.EnsureVisible(self.parent.txtDocument.LineFromPosition(self.findpos))
                self.parent.txtDocument.EnsureCaretVisible()
                self.parent.txtDocument.GotoPos(self.findpos)
                self.parent.txtDocument.SetSelectionStart(self.findpos)
                self.parent.txtDocument.SetSelectionEnd(self.findpos + len(self.textctrl.GetValue()))

                self.findpos -= 1
        else:
            self.parent.txtDocument.SetSelection (self.parent.IncrementalSearch_OldCursorPos, self.parent.IncrementalSearch_OldCursorPos)

    def OnProcessInput(self, event):
        key = event.GetKeyCode()
        shift = event.ShiftDown()
        alt = event.AltDown()
        self.bs = False
        if key == wx.WXK_ESCAPE:
            self.Destroy()
            self.parent.txtDocument.SetSelection (self.parent.IncrementalSearch_OldCursorPos, self.parent.IncrementalSearch_OldCursorPos)

        if key in [wx.WXK_DOWN, wx.WXK_UP, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_NEXT, wx.WXK_PRIOR]:
            self.Destroy()
            self.parent.txtDocument.SetSelection (self.parent.txtDocument.GetSelectionStart(), self.parent.txtDocument.GetSelectionStart())
            if key == wx.WXK_DOWN:
                self.parent.txtDocument.CmdKeyExecute(wx.stc.STC_CMD_LINEDOWN)
            if key == wx.WXK_UP:
                self.parent.txtDocument.CmdKeyExecute(wx.stc.STC_CMD_LINEUP)
            if key == wx.WXK_LEFT:
                self.parent.txtDocument.CmdKeyExecute(wx.stc.STC_CMD_CHARLEFT)
            if key == wx.WXK_RIGHT:
                self.parent.txtDocument.CmdKeyExecute(wx.stc.STC_CMD_CHARRIGHT)
            if key == wx.WXK_NEXT:
                self.parent.txtDocument.CmdKeyExecute(wx.stc.STC_CMD_PAGEDOWN)
            if key == wx.WXK_PRIOR:
                self.parent.txtDocument.CmdKeyExecute(wx.stc.STC_CMD_PAGEUP)

        if key == wx.WXK_BACK:
            if len (self.textctrl.GetValue()) > 1:
                self.bs = True
                self.findpos = self.parent.IncrementalSearch_OldCursorPos

        if key == wx.WXK_RETURN:
            if shift:
                self.FindPrevious()
            else:
                self.OnbtnNextFind(None)
        if alt:
            if key == ord ('P'):
                self.FindPrevious()
            elif key == ord ('N'):
                self.OnbtnNextFind (None)
        event.Skip()



def Plugin(DrFrame):

    def OnIncrementalSearch (event):
        DrFrame.IncrementalSearch_OldCursorPos = DrFrame.txtDocument.GetCurrentPos()
        ypos = DrFrame.GetSize()[1] + DrFrame.GetPosition()[1] - 32
        xpos = DrFrame.GetPosition()[0] + 150
        d = IncrementalSearchDlg(DrFrame, xpos, ypos)
        d.ShowModal()

    DrFrame.IncrementalSearch_OldCursorPos = -1
    ID_INCREMENTALSEARCH = DrFrame.GetNewId()


    DrFrame.Bind(wx.EVT_MENU, OnIncrementalSearch, id = ID_INCREMENTALSEARCH)

    DrFrame.AddPluginShortcutFunction("IncrementalSearch", "Incremental Search", OnIncrementalSearch)
    DrFrame.AddPluginPopUpMenuFunction("IncrementalSearch", "Incremental Search", OnIncrementalSearch)

    DrFrame.LoadPluginShortcuts('IncrementalSearch')
    DrFrame.searchmenu.AppendSeparator()
    DrFrame.searchmenu.Append(ID_INCREMENTALSEARCH, DrFrame.GetPluginMenuLabel('IncrementalSearch', 'Incremental Search', 'Incremental Search...'))


