#-----------------------------------------------------------------------------
# Name:        FindReplaceDlg.py
# Purpose:
#
# Authors:      Tim Hochberg, Ianare Sevi
#
# Created:     2001/29/08
# RCS-ID:      $Id: FindReplaceDlg.py,v 1.20 2007/07/02 15:01:04 riaan Exp $
# Copyright:   (c) 2001 - 2007 Tim Hochberg
# Licence:     GPL
#-----------------------------------------------------------------------------
#Boa:Dialog:FindReplaceDlg

import wx
from wx.lib.anchors import LayoutAnchors

import os, string

import Preferences, Utils
from Utils import _

from FindReplaceEngine import FindError

import Search

# XXX Should this return an indication of matches found?
def find(parent, finder, view):
    dlg = FindReplaceDlg(parent, finder, view)
    try:
        dlg.ShowModal()
    finally:
        dlg.Destroy()

def findAgain(parent, finder, view):
    if len(finder.findHistory) == 1:
        find(parent, finder, view)
    else:
        try:
            finder.findNextInSource(view)
        except FindError, err:
            wx.MessageBox(str(err), _('Find/Replace'), wx.OK | wx.ICON_INFORMATION, view)


[wxID_FINDREPLACEDLG, wxID_FINDREPLACEDLGBTNBROWSE, 
 wxID_FINDREPLACEDLGBTNBUILDINFIND, wxID_FINDREPLACEDLGBTNFINDINFILES, 
 wxID_FINDREPLACEDLGCANCELBTN, wxID_FINDREPLACEDLGCASESENSITIVECB, 
 wxID_FINDREPLACEDLGCHKRECURSIVESEARCH, wxID_FINDREPLACEDLGCLOSEONFOUNDCB, 
 wxID_FINDREPLACEDLGCMBFILEFILTER, wxID_FINDREPLACEDLGCMBFOLDER, 
 wxID_FINDREPLACEDLGDIRECTIONRB, wxID_FINDREPLACEDLGFINDALLBTN, 
 wxID_FINDREPLACEDLGFINDBTN, wxID_FINDREPLACEDLGFINDTXT, 
 wxID_FINDREPLACEDLGOPTIONSSB, wxID_FINDREPLACEDLGREGEXPRCB, 
 wxID_FINDREPLACEDLGREPLACEALLBTN, wxID_FINDREPLACEDLGREPLACEBTN, 
 wxID_FINDREPLACEDLGREPLACETXT, wxID_FINDREPLACEDLGSCOPERB, 
 wxID_FINDREPLACEDLGSTATICTEXT1, wxID_FINDREPLACEDLGSTATICTEXT2, 
 wxID_FINDREPLACEDLGSTATICTEXT3, wxID_FINDREPLACEDLGSTATICTEXT4, 
 wxID_FINDREPLACEDLGWHOLEWORDSCB, wxID_FINDREPLACEDLGWILDCARDCB, 
 wxID_FINDREPLACEDLGWRAPCB, 
] = [wx.NewId() for _init_ctrls in range(27)]

class FindReplaceDlg(wx.Dialog):    
    def _init_coll_topSizer_Growables(self, parent):
        # generated method, don't edit

        parent.AddGrowableCol(1)

    def _init_coll_chekboxSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.caseSensitiveCB, 0, border=3, flag=wx.BOTTOM)
        parent.AddWindow(self.wholeWordsCB, 0, border=3, flag=wx.BOTTOM)
        parent.AddWindow(self.wildcardCB, 0, border=3, flag=wx.BOTTOM)
        parent.AddWindow(self.regExprCB, 0, border=3, flag=wx.BOTTOM)
        parent.AddWindow(self.wrapCB, 0, border=3, flag=wx.BOTTOM)
        parent.AddWindow(self.closeOnFoundCB, 0, border=3, flag=wx.BOTTOM)
        parent.AddWindow(self.chkRecursiveSearch, 0, border=3, flag=wx.BOTTOM)

    def _init_coll_topSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.staticText2, 0, border=0,
              flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
        parent.AddSizer(self.findTxtSizer, 1, border=0, flag=wx.EXPAND)
        parent.AddWindow(self.staticText1, 0, border=0,
              flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
        parent.AddWindow(self.replaceTxt, 1, border=0, flag=wx.EXPAND)
        parent.AddWindow(self.staticText3, 0, border=0,
              flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
        parent.AddSizer(self.findFileSizer, 1, border=0, flag=wx.EXPAND)
        parent.AddWindow(self.staticText4, 0, border=0,
              flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)
        parent.AddWindow(self.cmbFolder, 1, border=0, flag=wx.EXPAND)

    def _init_coll_mainSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddSizer(self.topSizer, 0, border=5, flag=wx.ALL | wx.EXPAND)
        parent.AddSizer(self.bottomSizer, 1, border=2, flag=wx.TOP | wx.EXPAND)

    def _init_coll_findFileSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.cmbFileFilter, 1, border=0, flag=wx.EXPAND)
        parent.AddWindow(self.btnBrowse, 0, border=3,
              flag=wx.LEFT | wx.ALIGN_CENTER)

    def _init_coll_findTxtSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.findTxt, 1, border=0, flag=wx.ALIGN_CENTER)
        parent.AddWindow(self.btnBuildInFind, 0, border=3,
              flag=wx.LEFT | wx.ALIGN_CENTER)

    def _init_coll_radioBtnSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.directionRB, 0, border=0, flag=wx.ALIGN_CENTER)
        parent.AddWindow(self.scopeRB, 0, border=10,
              flag=wx.ALIGN_CENTER | wx.TOP)

    def _init_coll_buttonSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.findBtn, 0, border=4, flag=wx.EXPAND | wx.BOTTOM)
        parent.AddWindow(self.findAllBtn, 0, border=4,
              flag=wx.EXPAND | wx.BOTTOM)
        parent.AddWindow(self.btnFindInFiles, 0, border=4,
              flag=wx.EXPAND | wx.BOTTOM)
        parent.AddWindow(self.replaceBtn, 0, border=4,
              flag=wx.EXPAND | wx.BOTTOM)
        parent.AddWindow(self.replaceAllBtn, 0, border=4,
              flag=wx.EXPAND | wx.BOTTOM)
        parent.AddWindow(self.cancelBtn, 0, border=4,
              flag=wx.EXPAND | wx.BOTTOM)

    def _init_coll_bottomSizer_Items(self, parent):
        # generated method, don't edit

        parent.AddSizer(self.radioBtnSizer, 0, border=5,
              flag=wx.EXPAND | wx.RIGHT | wx.LEFT)
        parent.AddSizer(self.chekboxSizer, 1, border=5,
              flag=wx.BOTTOM | wx.EXPAND | wx.RIGHT)
        parent.AddSizer(self.buttonSizer, 0, border=5,
              flag=wx.EXPAND | wx.RIGHT)

    def _init_sizers(self):
        # generated method, don't edit
        self.mainSizer = wx.BoxSizer(orient=wx.VERTICAL)

        self.findTxtSizer = wx.BoxSizer(orient=wx.HORIZONTAL)

        self.findFileSizer = wx.BoxSizer(orient=wx.HORIZONTAL)

        self.bottomSizer = wx.BoxSizer(orient=wx.HORIZONTAL)

        self.radioBtnSizer = wx.BoxSizer(orient=wx.VERTICAL)

        self.buttonSizer = wx.BoxSizer(orient=wx.VERTICAL)

        self.chekboxSizer = wx.StaticBoxSizer(box=self.optionsSB,
              orient=wx.VERTICAL)

        self.topSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=0, vgap=5)

        self._init_coll_mainSizer_Items(self.mainSizer)
        self._init_coll_findTxtSizer_Items(self.findTxtSizer)
        self._init_coll_findFileSizer_Items(self.findFileSizer)
        self._init_coll_bottomSizer_Items(self.bottomSizer)
        self._init_coll_radioBtnSizer_Items(self.radioBtnSizer)
        self._init_coll_buttonSizer_Items(self.buttonSizer)
        self._init_coll_chekboxSizer_Items(self.chekboxSizer)
        self._init_coll_topSizer_Items(self.topSizer)
        self._init_coll_topSizer_Growables(self.topSizer)

        self.SetSizer(self.mainSizer)

    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Dialog.__init__(self, id=wxID_FINDREPLACEDLG, name='FindReplaceDlg',
              parent=prnt, pos=wx.Point(460, 453), size=wx.Size(460, 353),
              style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,
              title=_('Find/Replace'))
        self.SetClientSize(wx.Size(452, 324))

        self.findTxt = wx.ComboBox(choices=[], id=wxID_FINDREPLACEDLGFINDTXT,
              name='findTxt', parent=self, pos=wx.Point(93, 9),
              size=wx.Size(327, 21), style=0, value='')

        self.staticText2 = wx.StaticText(id=wxID_FINDREPLACEDLGSTATICTEXT2,
              label=_('Text to find'), name='staticText2', parent=self,
              pos=wx.Point(5, 5), size=wx.Size(83, 29), style=0)

        self.replaceTxt = wx.ComboBox(choices=[],
              id=wxID_FINDREPLACEDLGREPLACETXT, name='replaceTxt', parent=self,
              pos=wx.Point(93, 39), size=wx.Size(354, 21), style=0, value='')
        self.replaceTxt.Bind(wx.EVT_KEY_UP, self.OnFindtxtChar)

        self.staticText1 = wx.StaticText(id=wxID_FINDREPLACEDLGSTATICTEXT1,
              label=_('Replace with'), name='staticText1', parent=self,
              pos=wx.Point(5, 41), size=wx.Size(83, 17), style=0)

        self.cmbFolder = wx.ComboBox(choices=[],
              id=wxID_FINDREPLACEDLGCMBFOLDER, name='cmbFolder', parent=self,
              pos=wx.Point(93, 99), size=wx.Size(354, 21), style=0, value='')
        self.cmbFolder.SetLabel('')
        self.cmbFolder.SetToolTipString(_('Insert a path to find in files'))

        self.staticText3 = wx.StaticText(id=wxID_FINDREPLACEDLGSTATICTEXT3,
              label=_('Files to find in'), name='staticText3', parent=self,
              pos=wx.Point(5, 71), size=wx.Size(83, 17), style=0)

        self.cmbFileFilter = wx.ComboBox(choices=[],
              id=wxID_FINDREPLACEDLGCMBFILEFILTER, name='cmbFileFilter',
              parent=self, pos=wx.Point(93, 65), size=wx.Size(327, 21), style=0,
              value='*.py')
        self.cmbFileFilter.SetLabel('*.py')
        self.cmbFileFilter.SetToolTipString(_('Files that will be included in search'))

        self.staticText4 = wx.StaticText(id=wxID_FINDREPLACEDLGSTATICTEXT4,
              label=_('File filter'), name='staticText4', parent=self,
              pos=wx.Point(5, 99), size=wx.Size(83, 21), style=0)

        self.directionRB = wx.RadioBox(choices=[_('Forward'), _('Backward')],
              id=wxID_FINDREPLACEDLGDIRECTIONRB, label=_('Direction'),
              majorDimension=1, name='directionRB', parent=self, pos=wx.Point(5,
              127), size=wx.Size(91, 68), style=wx.RA_SPECIFY_COLS)
        self.directionRB.Bind(wx.EVT_RADIOBOX, self.OnDirectionrbRadiobox,
              id=wxID_FINDREPLACEDLGDIRECTIONRB)

        self.scopeRB = wx.RadioBox(choices=[_('All'), _('Selected')],
              id=wxID_FINDREPLACEDLGSCOPERB, label=_('Scope'), majorDimension=1,
              name='scopeRB', parent=self, pos=wx.Point(7, 205),
              size=wx.Size(86, 68), style=wx.RA_SPECIFY_COLS)
        self.scopeRB.Bind(wx.EVT_RADIOBOX, self.OnScoperbRadiobox,
              id=wxID_FINDREPLACEDLGSCOPERB)

        self.optionsSB = wx.StaticBox(id=wxID_FINDREPLACEDLGOPTIONSSB,
              label=_('Options'), name='optionsSB', parent=self,
              pos=wx.Point(101, 127), size=wx.Size(233, 192), style=0)

        self.caseSensitiveCB = wx.CheckBox(id=wxID_FINDREPLACEDLGCASESENSITIVECB,
              label=_('Case sensitive'), name='caseSensitiveCB', parent=self,
              pos=wx.Point(106, 144), size=wx.Size(116, 22), style=0)
        self.caseSensitiveCB.Bind(wx.EVT_CHECKBOX,
              self.OnCasesensitivecbCheckbox,
              id=wxID_FINDREPLACEDLGCASESENSITIVECB)

        self.wholeWordsCB = wx.CheckBox(id=wxID_FINDREPLACEDLGWHOLEWORDSCB,
              label=_('Whole words'), name='wholeWordsCB', parent=self,
              pos=wx.Point(106, 169), size=wx.Size(103, 22), style=0)
        self.wholeWordsCB.Bind(wx.EVT_CHECKBOX, self.OnWholewordscbCheckbox,
              id=wxID_FINDREPLACEDLGWHOLEWORDSCB)

        self.wildcardCB = wx.CheckBox(id=wxID_FINDREPLACEDLGWILDCARDCB,
              label=_('Wildcards'), name='wildcardCB', parent=self,
              pos=wx.Point(106, 194), size=wx.Size(84, 22), style=0)
        self.wildcardCB.Bind(wx.EVT_CHECKBOX, self.OnWildcardcbCheckbox,
              id=wxID_FINDREPLACEDLGWILDCARDCB)

        self.regExprCB = wx.CheckBox(id=wxID_FINDREPLACEDLGREGEXPRCB,
              label=_('Regular expressions'), name='regExprCB', parent=self,
              pos=wx.Point(106, 219), size=wx.Size(151, 22), style=0)
        self.regExprCB.Bind(wx.EVT_CHECKBOX, self.OnRegexprcbCheckbox,
              id=wxID_FINDREPLACEDLGREGEXPRCB)

        self.wrapCB = wx.CheckBox(id=wxID_FINDREPLACEDLGWRAPCB,
              label=_('Wrap search'), name='wrapCB', parent=self,
              pos=wx.Point(106, 244), size=wx.Size(102, 22), style=0)
        self.wrapCB.Bind(wx.EVT_CHECKBOX, self.OnWrapcbCheckbox,
              id=wxID_FINDREPLACEDLGWRAPCB)

        self.closeOnFoundCB = wx.CheckBox(id=wxID_FINDREPLACEDLGCLOSEONFOUNDCB,
              label=_('Close on found'), name='closeOnFoundCB', parent=self,
              pos=wx.Point(106, 269), size=wx.Size(195, 22), style=0)
        self.closeOnFoundCB.Bind(wx.EVT_CHECKBOX, self.OnCloseonfoundcbCheckbox,
              id=wxID_FINDREPLACEDLGCLOSEONFOUNDCB)

        self.chkRecursiveSearch = wx.CheckBox(id=wxID_FINDREPLACEDLGCHKRECURSIVESEARCH,
              label=_('Recursive search'), name='chkRecursiveSearch',
              parent=self, pos=wx.Point(106, 294), size=wx.Size(131, 22),
              style=0)
        self.chkRecursiveSearch.SetValue(False)

        self.findBtn = wx.Button(id=wxID_FINDREPLACEDLGFINDBTN, label=_('Find'),
              name='findBtn', parent=self, pos=wx.Point(339, 127),
              size=wx.Size(108, 27), style=0)
        self.findBtn.Bind(wx.EVT_BUTTON, self.OnFindbtnButton,
              id=wxID_FINDREPLACEDLGFINDBTN)
        self.findBtn.Bind(wx.EVT_KEY_UP, self.OnFindtxtChar)

        self.findAllBtn = wx.Button(id=wxID_FINDREPLACEDLGFINDALLBTN,
              label=_('Find all'), name='findAllBtn', parent=self,
              pos=wx.Point(339, 158), size=wx.Size(108, 28), style=0)
        self.findAllBtn.Bind(wx.EVT_BUTTON, self.OnFindallbtnButton,
              id=wxID_FINDREPLACEDLGFINDALLBTN)

        self.btnFindInFiles = wx.Button(id=wxID_FINDREPLACEDLGBTNFINDINFILES,
              label=_('Find in files'), name='btnFindInFiles', parent=self,
              pos=wx.Point(339, 190), size=wx.Size(108, 28), style=0)
        self.btnFindInFiles.Bind(wx.EVT_BUTTON, self.OnFindInFiles,
              id=wxID_FINDREPLACEDLGBTNFINDINFILES)

        self.replaceBtn = wx.Button(id=wxID_FINDREPLACEDLGREPLACEBTN,
              label=_('Replace'), name='replaceBtn', parent=self,
              pos=wx.Point(339, 222), size=wx.Size(108, 28), style=0)
        self.replaceBtn.Bind(wx.EVT_BUTTON, self.OnReplacebtnButton,
              id=wxID_FINDREPLACEDLGREPLACEBTN)

        self.replaceAllBtn = wx.Button(id=wxID_FINDREPLACEDLGREPLACEALLBTN,
              label=_('Replace all'), name='replaceAllBtn', parent=self,
              pos=wx.Point(339, 254), size=wx.Size(108, 28), style=0)
        self.replaceAllBtn.Bind(wx.EVT_BUTTON, self.OnReplaceallbtnButton,
              id=wxID_FINDREPLACEDLGREPLACEALLBTN)

        self.cancelBtn = wx.Button(id=wx.ID_CANCEL, label=_('Cancel'),
              name='cancelBtn', parent=self, pos=wx.Point(339, 286),
              size=wx.Size(108, 28), style=0)

        self.btnBuildInFind = wx.Button(id=wxID_FINDREPLACEDLGBTNBUILDINFIND,
              label='...', name='btnBuildInFind', parent=self, pos=wx.Point(423,
              5), size=wx.Size(24, 29), style=wx.BU_EXACTFIT)
        self.btnBuildInFind.SetToolTipString(_('Build-in ready to run searches'))
        self.btnBuildInFind.Bind(wx.EVT_BUTTON, self.OnBuildInFind,
              id=wxID_FINDREPLACEDLGBTNBUILDINFIND)

        self.btnBrowse = wx.Button(id=wxID_FINDREPLACEDLGBTNBROWSE, label='...',
              name='btnBrowse', parent=self, pos=wx.Point(423, 65),
              size=wx.Size(24, 29), style=wx.BU_EXACTFIT)
        self.btnBrowse.SetToolTipString(_('Folders tree'))
        self.btnBrowse.Bind(wx.EVT_BUTTON, self.OnBrowse,
              id=wxID_FINDREPLACEDLGBTNBROWSE)

        self._init_sizers()

    def __init__(self, parent, engine, view, bModeFindReplace = 1):
        self._init_ctrls(parent)
        
        # reset all sizes to default
        Utils.resetMinSize(self)
        
        # now set the sizer properly
        self.SetSizerAndFit(self.mainSizer)
        
        self.engine = engine
        self.view = view
        # Bind enter event using acceleratorTable
        wxID_FINDRETURN = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnFindtxtTextEnter, id=wxID_FINDRETURN)
        self.findTxt.SetAcceleratorTable(wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_RETURN, wxID_FINDRETURN)]))
        wxID_REPLACERETURN = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnReplacetxtTextEnter, id=wxID_REPLACERETURN)
        self.replaceTxt.SetAcceleratorTable(wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_RETURN, wxID_FINDRETURN)]))
        # Set controls based on engine
        self.setComboBoxes('init')
        self.caseSensitiveCB.SetValue(engine.case)
        self.wholeWordsCB.SetValue(engine.word)
        self.regExprCB.SetValue(engine.mode == 'regex')
        self.wildcardCB.SetValue(engine.mode == 'wildcard')
        self.wrapCB.SetValue(engine.wrap)
        self.closeOnFoundCB.SetValue(engine.closeOnFound)
        self.directionRB.SetSelection(engine.reverse)
        self.scopeRB.SetSelection(self.engine.selection)
        # Check if the view is a package
        if hasattr(view, 'viewName'):
            if view.viewName in ("Package", "Application"):
                self.replaceTxt.Enable(False)
                self.findBtn.Enable(False)
                self.replaceBtn.Enable(False)
                self.replaceAllBtn.Enable(False)
                self.findAllBtn.SetDefault()
            else:
                # Otherwise, for findTxt, use the selected text if it's all on one
                # line, otherwise use the most recent item in the history.
                text = view.GetSelectedText()
                selStart, selEnd = self.view.GetSelection()
                if selStart != selEnd and '\n' not in text:
                    self.findTxt.SetValue(text)
                    self.findTxt.SetMark(0, len(text))
                # Use this region for future search replaces over selected.
                engine.setRegion(view, view.GetSelection())
                self.findBtn.SetDefault()

        # Give the find entry focus
        self.findTxt.SetFocus()

        wxID_DOFIND = wx.NewId()
        wxID_DOREPLACE = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnFindbtnButton, id=wxID_DOFIND)
        self.Bind(wx.EVT_MENU, self.OnReplacebtnButton, id=wxID_DOREPLACE)
        # bug in wxPython, esc key not working
        self.SetAcceleratorTable(
              wx.AcceleratorTable([ Utils.setupCloseWindowOnEscape(self),
                                  (wx.ACCEL_NORMAL, wx.WXK_F3, wxID_DOFIND),
                                  (wx.ACCEL_CTRL, wx.WXK_F3, wxID_DOREPLACE),
                                  ]))

        # workaround for above bug, bind key evt to all ctrls
        for ctrl in (self.findTxt, self.replaceTxt, self.directionRB, self.scopeRB,
                     self.optionsSB, self.caseSensitiveCB, self.wholeWordsCB,
                     self.wildcardCB, self.regExprCB, self.wrapCB,
                     self.closeOnFoundCB, self.findBtn, self.findAllBtn,
                     self.replaceBtn, self.replaceAllBtn, self.cancelBtn):
            ctrl.Bind(wx.EVT_KEY_UP, self.OnFindtxtChar)

        if not bModeFindReplace:
            self.findAllBtn.Enable(False)
            self.findBtn.Enable(False)
            self.replaceBtn.Enable(False)
            self.replaceAllBtn.Enable(False)
            self.engine.closeOnFound = True
            self.closeOnFoundCB.SetValue(engine.closeOnFound)
            self.directionRB.Enable(False)
            self.scopeRB.Enable(False)
            self.btnFindInFiles.SetDefault()

        self.Center()

        self._mapBuildInFinds = {
            'Derived classes':'\s*class\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(.*[^a-zA-Z0-9_]?XXXX[^a-zA-Z0-9_]?.*\)',
            'Class definition':'\s*class\s+XXXX(\s|[^a-zA-Z0-9_])',
            'Function\method definition':'\s*def\s+XXXX(\s|[^a-zA-Z0-9_])',
            'Class member':'(\s|[^a-zA-Z0-9_])self\.+XXXX(\s|[^a-zA-Z0-9_])'
        }

    def SetWorkingFolder(self, folder):
        self.cmbFolder.SetValue(folder)

    def setComboBoxes(self, setWhat):
        # We discard the empty item at the start of the history unless
        # It's the only item -- this make the list box look better.
        self.findTxt.Clear()
        history = self.engine.findHistory[1:] or ['']
        history.reverse()
        for x in history:
            self.findTxt.Append(x)
        self.findTxt.SetValue(history[0])
        self.findTxt.SetMark(0, len(history[0]))

        try:
            working_folder = os.path.dirname(self.view.model.localFilename())
        except:
            working_folder = ''

        self.cmbFolder.Clear()
        history = self.engine.folderHistory[1:] or [working_folder]
        history.reverse()
        for x in history:
            self.cmbFolder.Append(x)
        self.cmbFolder.SetValue(history[0])

        history = self.engine.suffixHistory[1:] or ['*.py']
        history.reverse()
        for x in history:
            self.cmbFileFilter.Append(x)
        self.cmbFileFilter.SetValue(history[0])

        if setWhat in ['init', 'replace']:
            self.replaceTxt.Clear()
            history = self.engine.replaceHistory[1:] or ['']
            history.reverse()
            for x in history:
                self.replaceTxt.Append(x)
            self.replaceTxt.SetValue(history[0])

    def OnFindbtnButton(self, event):
        self.find()

    def find(self):
        try:
            pattern = self.findTxt.GetValue()
            self.engine.findInSource(self.view, pattern)
            self.setComboBoxes('find')
            if self.engine.closeOnFound and not self.replaceTxt.GetValue():
                self.EndModal(wx.ID_OK)
            else:
                self._checkSelectionDlgOverlap()
        except FindError, err:
            wx.MessageBox(str(err), _('Find/Replace'), wx.OK | wx.ICON_INFORMATION, self)

    def findAll(self):
        pattern = self.findTxt.GetValue()
        if self.view.viewName == "Package":
            self.engine.findAllInPackage(self.view, pattern)
        elif self.view.viewName == "Application":
            self.engine.findAllInApp(self.view, pattern)
        else:
            self.engine.findAllInSource(self.view, pattern)
        self.setComboBoxes('find')
        self.EndModal(wx.ID_OK)

    def replace(self):
        try:
            pattern = self.findTxt.GetValue()
            replacement = self.replaceTxt.GetValue()
            self.engine.replaceInSource(self.view, pattern, replacement)
            self._checkSelectionDlgOverlap()
            self.setComboBoxes('replace')
        except FindError, err:
            wx.MessageBox(str(err), _('Find/Replace'), wx.OK | wx.ICON_INFORMATION, self)

    def replaceAll(self):
        pattern = self.findTxt.GetValue()
        replacement = self.replaceTxt.GetValue()
        self.engine.replaceAllInSource(self.view, pattern, replacement)
        self.setComboBoxes('replace')
        self.EndModal(wx.ID_OK)

    def findInFiles(self):
        names = []
        pattern = self.findTxt.GetValue()
        bRecursive = self.chkRecursiveSearch.GetValue()
        file_filter = string.split(self.cmbFileFilter.GetValue(), ';')
        folder = [self.cmbFolder.GetValue()]
        self.engine.addFolder(folder[0])
        self.engine.addSuffix(self.cmbFileFilter.GetValue())
        dlg = wx.ProgressDialog(_("Building file list from directory '%s'") % (folder[0]),
                       _('Searching...'), 100, self.view,
                        wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_AUTO_HIDE)
        try:
            iterDirFiles = Search.listFiles(folder, file_filter, 1, bRecursive)
            iStep = 0
            for sFile in iterDirFiles:
                names.append(sFile)
                if iStep < 100 and not dlg.Update(iStep):
                    #self.view.model.editor.setStatus('Search aborted')
                    break
                iStep = iStep + 1
        finally:
            dlg.Destroy()
        self.engine.findAllInFiles(names, self.view, pattern )
        self.setComboBoxes('findInFiles')
        if self.engine.closeOnFound:
            self.EndModal(wx.ID_OK)


    def _validate(self, what):
        ##Doesn't matter how we want to search we need smth to search to.
        if not self.findTxt.GetValue():
            wx.MessageBox(_('There is nothing to find.'), _('Boa - Find/Replace'))
            return False
        if what in ['find', 'findAll']:
            pass
        elif what in ['replace', 'replaceAll']:
            if not self.replaceTxt.GetValue():
                wx.MessageBox(_('There is nothing to replace with.'), _('Boa - Find/Replace'))
                return False
        elif what == 'findInFiles':
            if not os.path.isdir( self.cmbFolder.GetValue() ):
                wx.MessageBox(_('The folder you entered is not valid folder.'), _('Boa - Find/Replace'))
                return False
        else:
            pass
        return True

    def OnDirectionrbRadiobox(self, event):
        self.engine.reverse = self.directionRB.GetSelection()

    def OnCasesensitivecbCheckbox(self, event):
        self.engine.case = self.caseSensitiveCB.GetValue()

    def OnWholewordscbCheckbox(self, event):
        self.engine.word = self.wholeWordsCB.GetValue()

    def OnRegexprcbCheckbox(self, event):
        if self.regExprCB.GetValue():
            self.wildcardCB.SetValue(0)
        mode = {(0,0) : 'text', (1,0) : 'regex', (0,1) : 'wildcard'}[
                    (self.regExprCB.GetValue(), self.wildcardCB.GetValue())]
        self.engine.mode = mode

    def OnFindtxtTextEnter(self, event):
        if self.view.viewName in ('Package', 'Application'):
            if self._validate('findAll'):
                self.findAll()
        else:
            if self._validate('find'):
                self.find()

    def OnReplacebtnButton(self, event):
        if self._validate('replace'):
            self.replace()

    def OnFindallbtnButton(self, event):
        if self._validate('findAll'):
            self.findAll()

    def OnReplacetxtTextEnter(self, event):
        if self._validate('replace'):
            self.replace()

    def OnReplaceallbtnButton(self, event):
        if self._validate('replaceAll'):
            self.replaceAll()

    def OnFindInFiles(self, event):
        if self._validate('findInFiles'):
            self.findInFiles()

    def OnScoperbRadiobox(self, event):
        self.engine.selection = self.scopeRB.GetSelection()

    def OnWrapcbCheckbox(self, event):
        self.engine.wrap = int(self.wrapCB.GetValue())

    def OnCloseonfoundcbCheckbox(self, event):
        self.engine.closeOnFound = int(self.closeOnFoundCB.GetValue())

    _fudgeOffset = 6
    def _checkSelectionDlgOverlap(self):
        if self.view.viewName not in ('Package', 'Application'):
            selStart, selEnd = self.view.GetSelection()
            selStartLnNo = self.view.LineFromPosition(selStart)
            if selStart != selEnd and selStartLnNo == self.view.LineFromPosition(selEnd):
                chrHeight = self.view.GetCharHeight()
                selPos = self.view.ClientToScreen(self.view.PointFromPosition(selStart))
                selSize = wx.Size(self.view.ClientToScreen(
                      self.view.PointFromPosition(selEnd)).x - selPos.x, chrHeight)
                dlgPos, dlgSize = self.GetPosition(), self.GetSize()
                r = wx.IntersectRect(wx.Rect(selPos.x, selPos.y, selSize.x, selSize.y),
                                    wx.Rect(dlgPos.x, dlgPos.y, dlgSize.x, dlgSize.y))
                if r is not None:
                    # simply moves dialog above or below selection
                    # sometimes rather moving it to the sides would be more
                    # appropriate
                    mcp = self.ScreenToClient(wx.GetMousePosition())
                    if selStartLnNo < self.view.GetFirstVisibleLine() + \
                          self.view.LinesOnScreen()/2:
                        self.SetPosition( (dlgPos.x, selPos.y + chrHeight + self._fudgeOffset) )
                    else:
                        self.SetPosition( (dlgPos.x, selPos.y - dlgSize.y - self._fudgeOffset) )
                    self.WarpPointer(mcp.x, mcp.y)

    def OnWildcardcbCheckbox(self, event):
        if self.wildcardCB.GetValue():
            self.regExprCB.SetValue(0)
        mode = {(0,0) : 'text', (1,0) : 'regex', (0,1) : 'wildcard'}[
                    (self.regExprCB.GetValue(), self.wildcardCB.GetValue())]
        self.engine.mode = mode

    def OnFindtxtChar(self, event):
        if event.GetKeyCode() == wx.WXK_ESCAPE:
            self.Close()
        event.Skip()

    def OnBuildInFind(self, event):
        dlg = wx.SingleChoiceDialog(self, _('Find'), _('Build in finds'), self._mapBuildInFinds.keys())
        try:
            if dlg.ShowModal() == wx.ID_OK:
                selected = dlg.GetStringSelection()
                self.findTxt.SetValue(self._mapBuildInFinds[selected])
                self.regExprCB.SetValue(1)
                self.OnRegexprcbCheckbox(None)
        finally:
            dlg.Destroy()

        self.findBtn.SetFocus()


    def browseForDir(self, strFromFolder=''):
        strPath = ''
        dlgDirDialog = wx.DirDialog(self)
        dlgDirDialog.SetPath( strFromFolder )
        if dlgDirDialog.ShowModal() == wx.ID_OK:
            strPath = dlgDirDialog.GetPath()
        dlgDirDialog.Destroy()
        return strPath

    def OnBrowse(self, event):
        strNewPath = self.browseForDir()
        if strNewPath:
            self.cmbFolder.SetValue(strNewPath)

        self.findBtn.SetFocus()


if __name__ == '__main__':
    app = wx.PySimpleApp()
    testText = '''Find replace dialog test



Boa boa keyboard        bOa boa keyboard        boA boa keyboard
quick brown fox jumps over the lazy dog
\n\n\n\n\n\n\n\n
Boa Constructor         Boa Constructor         Boa Constructor
'''
    # Create a simple test environment (RB)

    def createFramedView(caption, View, model, parent=None, size=wx.DefaultSize):
        f = wx.Frame(parent, -1, caption, size=size)
        v = View(f, model)
        f.Center()
        f.Show(1)
        return f, v

    class PseudoStatusBar:
        def setHint(self, hint, htype='Info'): wx.LogMessage('Editor hint: %s'%hint)
    class PseudoEditor:
        def __init__(self): self.statusBar = PseudoStatusBar()
        def addBrowseMarker(self, lineNo): pass
        def addNewView(self, name, View): return createFramedView(name, View, self.model, self.parent, (400, 200))[1]
        def Disconnect(self, id): pass
        def setStatus(self, hint, htype='Info', ringBell=False): wx.LogMessage('Editor hint: %s'%hint)

    e = PseudoEditor()
    from Models.PythonEditorModels import ModuleModel
    m = ModuleModel(testText, 'test.py', e, True)
    from Views.PySourceView import PythonSourceView
    f, v = createFramedView('Find/Replace Dlg Tester (Cancel to quit)', PythonSourceView, m, size=(600, 400))
    v.refreshCtrl()
    e.model, e.parent = m, f
    from FindReplaceEngine import FindReplaceEngine
    finder = FindReplaceEngine()
    finder.addFind('boa')
    res = 0
    while res != wx.ID_CANCEL:
        dlg = FindReplaceDlg(f, finder, v)
        try: res = dlg.ShowModal()
        finally: dlg.Destroy()
        if res != wx.ID_CANCEL: wx.LogMessage('Reopening dialog for testing')
