
'''
This software is licensed under the GPL (GNU General Public License) version 2
as it appears here: http://www.gnu.org/copyleft/gpl.html
It is also included with this archive as `gpl.txt <gpl.txt>`_.
'''


import re
import wx
import wx.stc

import scheduler

class OnCloseBar: #embedded callback to destroy the findbar on removal
    def __init__(self, control):
        self.c = control
    def __call__(self, *args):
        self.c.savePreferences()
        self.c.parent.Unsplit()
        self.c.Destroy()
        del self.c

word = dict.fromkeys(map(ord, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'))
non_word = dict.fromkeys([chr(i) for i in xrange(256) if i not in word])

MEM_LEAK_TEST = 0
OCOUNTLIMIT = COUNTLIMIT = 20

class ReplaceBar(wx.Panel):
    def __init__(self, parent, root):
        #init the object
        wx.Panel.__init__(self, parent, style=wx.NO_BORDER|wx.TAB_TRAVERSAL)
        self.parent = parent
        self.root = root
        
        #state variables
        self._lastcall = self.OnFindN
        self.incr = 1
        self.loop = 0
        self.shiftdown = 0
        self.buttons = []
        self.replacing = 0
        self.wholeword = 0
        
        self.replace_t = Timer(self._replace_again1, None)
        self._replace_args = None
        
        self.replace_t2 = Timer(self._re_replace_again1, None)
        self._re_replace_args = None
        
        prefs = self.readPreferences()
        self.setup()
        
    def setup(self):
        """
        Layout the panel controls.
        """
        
        prefs = self.preferences
        
        self.sizer = wx.GridBagSizer(5, 5)
        
        #textbox
        if self.root.getglobal('no_findbar_history'):
            self.box1 = box1 = wx.TextCtrl(self, -1, size=(125, -1), style=wx.TE_PROCESS_ENTER)
        else:
            self.box1 = box1 = wx.ComboBox(self, -1, choices=prefs['find'], size=(125, -1), style=wx.TE_PROCESS_ENTER)
            if prefs['find']:
                box1.SetStringSelection(prefs['find'][0])
            box1.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
        #box1.SetInsertionPoint(0)
        box1.Bind(wx.EVT_TEXT, self.OnChar)
        box1.Bind(wx.EVT_TEXT_ENTER, self.OnEnter)
        box1.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        box1.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
        box1.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
        self.box1 = box1
        self.sizer.Add(box1, (0,0), flag=wx.EXPAND|wx.RIGHT, border=5)
        
        #find next and previous buttons
        self.addbutton(self.sizer, self, "Find Next", self.OnFindN, (0,1))
        self.addbutton(self.sizer, self, "Find Previous", self.OnFindP, (0,2))
        
        #match case toggle, along with re-calling the last find operation when
        #it is switched
        if DOUBLE_ROW_ONE:
            ss = wx.BoxSizer(wx.VERTICAL)
        if USE_BOX_SIZERS and not DOUBLE_ROW_ONE:
            ss = wx.BoxSizer(wx.HORIZONTAL)
        
        self.case = wx.CheckBox(self, -1, "Match Case")
        if USE_MINI_CHECKBOXES:
            self.case.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
        if USE_BOX_SIZERS or DOUBLE_ROW_ONE:
            ss.Add(self.case, flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border=5)
        else:
            self.sizer.Add(self.case, (0,3), flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border=5)
        self.case.SetValue(prefs['case'])
        self.wrap = wx.CheckBox(self, -1, "Wrap Search")
        if USE_MINI_CHECKBOXES:
            self.wrap.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
        self.wrap.SetValue(prefs['wrap'])
        if USE_BOX_SIZERS or DOUBLE_ROW_ONE:
            ss.Add(self.wrap, flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border=5)
        else:
            self.sizer.Add(self.wrap, (0,4), flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border=5)
        
        if DOUBLE_ROW_ONE:
            if not USE_BOX_SIZERS:
                self.sizer.Add(ss, (0,3), flag=wx.EXPAND|wx.RIGHT, border=5)
            else:
                ss2 = wx.BoxSizer(wx.HORIZONTAL)
                ss2.Add(ss, 0, wx.EXPAND|wx.RIGHT, border=5)
                ss = ss2
        
        #close button
        self.close = OnCloseBar(self)
        if USE_BOX_SIZERS:
            ss.Add(wx.StaticText(self), 1, wx.EXPAND)
            self.closebutton = self.addbutton(ss, self, "Close", self.close, 0)
            self.sizer.Add(ss, (0,3), flag=wx.EXPAND)
        else:
            self.closebutton = self.addbutton(self.sizer, self, "Close", self.close, (0,5-bool(DOUBLE_ROW_ONE)))
        
        if isinstance(self, FindBar):
            self.box1.MoveAfterInTabOrder(self.closebutton)
            return self.finish_setup()
        
        if self.root.getglobal('no_findbar_history'):
            self.box2 = box2 = wx.TextCtrl(self, -1, size=(125, -1))
        else:
            self.box2 = box2 = wx.ComboBox(self, -1, choices=prefs['replace'], size=(125, -1))
            if prefs['replace']:
                box2.SetStringSelection(prefs['replace'][0])
        box2.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
        self.sizer.Add(box2, (1,0), flag=wx.EXPAND|wx.RIGHT, border=5)
        
        self.addbutton(self.sizer, self, "Replace", self.OnReplace, (1,1))
        self.addbutton(self.sizer, self, "Replace All", self.OnReplaceAll, (1,2))
        
        ss = wx.BoxSizer(wx.HORIZONTAL)
        if USE_BOX_SIZERS:
            self.addbutton(ss, self, "Replace in Selection", self.OnReplaceSel, 0)
        else:
            self.addbutton(self.sizer, self, "Replace in Selection", self.OnReplaceSel, (1,3))
        self.smartcase = wx.CheckBox(self, -1, "Smart Case")
        if USE_MINI_CHECKBOXES:
            self.smartcase.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
        self.smartcase.SetValue(prefs['smartcase'])
        if USE_BOX_SIZERS:
            ss.Add(self.smartcase, flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, border=5)
            self.sizer.Add(ss, (1,3), flag=wx.EXPAND)
        else:
            self.sizer.Add(self.smartcase, (1,4), flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT)
        
        self.box1.MoveAfterInTabOrder(self.smartcase)
        self.finish_setup()

    def finish_setup(self):
        self.sizer.AddGrowableCol(0)
        
        self.sizer.Fit(self)
        self.SetSizer(self.sizer)

    def addbutton(self, sizer, control, alt, fcn, pos):
        t2 = wx.Button(control, -1, alt, style=wx.NO_BORDER)
        wx.EVT_BUTTON(control, t2.GetId(), fcn)
        flags = wx.RIGHT
        if type(pos) is tuple:
            #first row buttons are longer than second row buttons
            if pos[0] == 0:
                flags |= wx.ALIGN_CENTER_VERTICAL
            else:
                flags |= wx.EXPAND
        border = 5
        if alt == 'Close':
            #move the close button to the right
            flags |= wx.ALIGN_RIGHT
            #remove the right border on the close button
            flags ^= wx.RIGHT
        sizer.Add(t2, pos, flag=flags, border=5)
        if type(pos) is tuple and pos[1] == 1:
            self.buttons.append(t2)
        return t2

    def status(self, text):
        self.root.SetStatusText(text, log=0)

    def lastcall(self, evt):
        self._lastcall(evt)

    def OnChar(self, evt):
        #handle updating the background color
        if self.box1.GetBackgroundColour() != wx.WHITE:
            self.box1.SetBackgroundColour(wx.WHITE)
            self.status('')
            self.Refresh()
        
        if not isinstance(self, FindBar):
            return

        #search in whatever direction we were before
        if self._lastcall == self.OnFindN:
            self._lastcall(evt, 1)

    def OnNotFound(self):
        self.box1.SetBackgroundColour(wx.RED)
        self.status("Search string was not found.")
        self.Refresh()

    def getFinds(self, evt, which=0):
        findTxt = self.box1
        if which:
            findTxt = self.box2
        findTxt = findTxt.GetValue()
        matchcase = self.case.GetValue() and wx.FR_MATCHCASE
        if not findTxt:
            if not which:
                if evt:
                    evt.Skip()
                raise cancelled
            return "", None, None
        
        #python strings in find automatically handled
        findTxt = self.root.getglobal('str_unrepr')(findTxt)
       
        #nothing to find!
        if not findTxt:
            if not which:
                if evt:
                    evt.Skip()
                raise cancelled
            return "", None, None
        
        win = self.parent.GetWindow1()
        return findTxt, matchcase, win

    def sel(self, posns, posne, msg, win):
        if self.box1.GetBackgroundColour() != wx.WHITE:
            self.box1.SetBackgroundColour(wx.WHITE)
            self.status('')
            self.Refresh()
        self.status(msg)
        line = win.LineFromPosition(posns)
        win.GotoLine(line)
        posns, posne = self.getRange(win, posns, posne-posns)
        win.SetSelection(posns, posne)
        win.EnsureVisible(line)
        win.EnsureCaretVisible()
    
    def getRange(self, win, start, chars, dire=1):
        end = start
        if dire==1:
            fcn = win.PositionAfter
        else:
            fcn = win.PositionBefore
        for i in xrange(chars):
            z = fcn(end)
            y = win.GetCharAt(end)
            x = abs(z-end)==2 and (((dire==1) and (y == 13)) or ((dire==0) and (y == 10)))
            ## print y, z-end
            end = z - x
        return start, end
    
    def isWholeWord(self, start, chars, win):
        #we may need to use this for unicode whole word checks
        start, end = self.getRange(win, start, chars)
        if start != 0:
            if win.GetCharAt(win.PositionBefore(start)) not in non_word:
                return 0
        
        if end != win.GetTextLength():
            if win.GetCharAt(win.PositionAfter(end)) not in non_word:
                return 0
        
        return 1

    def OnFindN(self, evt, incr=0):
        self._lastcall = self.OnFindN
        self.incr = incr
        findTxt, matchcase, win = self.getFinds(evt)
        flags = wx.FR_DOWN|matchcase
        if self.wholeword:
            flags |= wx.stc.STC_FIND_WHOLEWORD
        
        #handle finding next item, handling wrap-arounds as necessary
        gs = win.GetSelection()
        gs = min(gs), max(gs)
        st = gs[1-incr]
        posn = win.FindText(st, win.GetTextLength(), findTxt, flags)
        if posn != -1:
            self.sel(posn, posn+len(findTxt), '', win)
            self.loop = 0
            return
        
        if self.wrap.GetValue() and st != 0:
            posn = win.FindText(0, win.GetTextLength(), findTxt, flags)
        self.loop = 1
        
        if posn != -1:
            self.sel(posn, posn+len(findTxt), "Reached end of document, continued from start.", win)
            return
        
        self.OnNotFound()
    
    def OnFindP(self, evt, incr=0):
        self._lastcall = self.OnFindP
        self.incr = 0
        findTxt, matchcase, win = self.getFinds(evt)
        flags = matchcase
        if self.wholeword:
            flags |= wx.stc.STC_FIND_WHOLEWORD
        
        
        #handle finding previous item, handling wrap-arounds as necessary
        st = min(self.getRange(win, min(win.GetSelection()), len(findTxt), 0))
        #print win.GetSelection(), st, 
        posn = win.FindText(st, 0, findTxt, flags)
        if posn != -1:
            self.sel(posn, posn+len(findTxt), '', win)
            self.loop = 0
            return
        
        if self.wrap.GetValue() and st != win.GetTextLength():
            posn = win.FindText(win.GetTextLength(), 0, findTxt, flags)
        self.loop = 1
        
        if posn != -1:
            self.sel(posn, posn+len(findTxt), "Reached start of document, continued from end.", win)
            return
        
        self.OnNotFound()
    
    def OnKeyDown(self, evt):
        if self.FindFocus() == self.box1:
            self.wholeword = 0
        kc = evt.GetKeyCode()
        if kc == wx.WXK_ESCAPE:
            p = self.parent.GetWindow1()
            self.close()
            p.SetFocus()
            return
        elif kc == wx.WXK_SHIFT and self.FindFocus() == self.box1:
            self.shiftdown = 1
        elif kc == wx.WXK_TAB:
            foc = self.FindFocus()
            if foc == self.box1:
                return self.buttons[0].SetFocus()
            elif len(self.buttons) == 2 and foc == self.box2:
                return self.buttons[1].SetFocus()
        if evt:
            evt.Skip()
    
    def OnKeyUp(self, evt):
        if evt.GetKeyCode() == wx.WXK_SHIFT:
            self.shiftdown = 0
        if evt:
            evt.Skip()
    
    def OnEnter(self, evt):
        if self.shiftdown:
            return self.OnFindP(evt)
        return self.OnFindN(evt)
    
    def OnKillFocus(self, evt):
        self.shiftdown = 0
        if evt:
            evt.Skip()
    
    def OnSetFocus(self, evt):
        self.box1.SetMark(0, self.box1.GetLastPosition())
        if evt:
            evt.Skip()

    def OnReplace(self, evt):
        findTxt, matchcase, win = self.getFinds(evt)
        sel = win.GetSelection()
        if sel[0] == sel[1]:
            self.OnFindN(evt)
            return (-1, -1), 0
        else:
            a = win.GetTextRange(sel[0], sel[1])
            if (matchcase and a != findTxt) or \
               (not matchcase and a.lower() != findTxt.lower()):
                self.OnFindN(evt)
                return (-1, -1), 0
            
        
        replaceTxt = self.getFinds(None, 1)[0]
        findTxt = a
        
        if self.smartcase.GetValue():
            if findTxt.upper() == findTxt:
                ## print "all upper", findTxt
                replaceTxt = replaceTxt.upper()
            elif findTxt.lower() == findTxt:
                ## print "all lower", findTxt
                replaceTxt = replaceTxt.lower()
            elif len(findTxt) == len(replaceTxt):
                ## print "smartcasing", findTxt
                r = []
                for i,j in zip(findTxt, replaceTxt):
                    if i.isupper():
                        r.append(j.upper())
                    elif i.islower():
                        r.append(j.lower())
                    else:
                        r.append(j)
                replaceTxt = ''.join(r)
            elif findTxt and replaceTxt and findTxt[:1].upper() == findTxt[:1]:
                ## print "first upper", findTxt
                replaceTxt = replaceTxt[:1].upper() + replaceTxt[1:]
            elif findTxt and replaceTxt and findTxt[:1].lower() == findTxt[:1]:
                ## print "first lower", findTxt
                replaceTxt = replaceTxt[:1].lower() + replaceTxt[1:]
        
        sel = win.GetSelection()
        if win.CanEdit():
            win.ReplaceSelection(replaceTxt)
            #fix for unicode...
            win.SetSelection(min(sel), min(sel)+len(replaceTxt))
            self.OnFindN(evt)
            
            return sel, len(findTxt)-len(replaceTxt)
        else:
            return (max(sel), max(sel)), 0
    
    def _replaceAll(self, evt, ris):
        win = self.parent.GetWindow1()
        ostart, oend = win.GetSelection()
        
        #ris = self.replinsel.GetValue()
        win.BeginUndoAction()
        try:
            if ris:
                win.SetSelection(ostart, ostart)
            else:
                win.SetSelection(0, 0)
            
            self.loop = 0
            failed = 0
            while not self.loop and failed < 2:
                #check for range...
                sel = win.GetSelection()
                if ris and (sel[0] < ostart or sel[1] > oend):
                    break
                #find/replace next item
                (lsel, rsel), delta = self.OnReplace(evt)
                ## print (lsel, rsel), delta, repr(win.GetTextRange(lsel, rsel)), self.loop
                #if nothing found, continue
                if lsel == -1:
                    continue
                #if change was entirely in the old selection...
                elif ostart <= lsel and rsel <= oend:
                    oend -= delta
                #original selection is encompassed by the replacement.
                elif lsel <= ostart and rsel >= oend:
                    ostart = oend = lsel
                #replaced portion is to the left of the original selection
                elif rsel < ostart:
                    ostart -= delta
                    oend -= delta
                try:
                    wx.Yield()
                except:
                    pass
            ## print self.loop, failed
            
            self.sel(ostart, oend, '', win)
            win.SetFocus()
        finally:
            win.EndUndoAction()
    
    def replaceAll(self, evt, ris):
        win = self.parent.GetWindow1()
        ostart, oend = win.GetSelection()
        
        #ris = self.replinsel.GetValue()
        if not MEM_LEAK_TEST: win.BeginUndoAction()
        if ris:
            win.SetSelection(ostart, ostart)
        else:
            win.SetSelection(0, 0)
        self.OnFindN(None, ris)
        
        self.replacing = 1
        wx.CallAfter(self.ReentrantReplace, (ostart, oend, ris, win))

    def ReentrantReplace(self, state):
        global COUNTLIMIT
        COUNTLIMIT = min(1000, int(COUNTLIMIT*1.5))
        ostart, oend, ris, win = state
        
        if not win:
            return
        
        try:
            self.loop
        except:
            return
        
        cont = 1
        count = 0
        while not self.loop:
            sel = win.GetSelection()
            if ris and (sel[0] < ostart or sel[1] > oend):
                cont = 0
                break
            #find/replace next item
            (lsel, rsel), delta = self.OnReplace(None)
            ## print (lsel, rsel), delta, repr(win.GetTextRange(lsel, rsel)), self.loop
            #if nothing found, continue
            if lsel == -1:
                continue
            #if change was entirely in the old selection...
            elif ostart <= lsel and rsel <= oend:
                oend -= delta
            #original selection is encompassed by the replacement.
            elif lsel <= ostart and rsel >= oend:
                ostart = oend = lsel
            #replaced portion is to the left of the original selection
            elif rsel < ostart:
                ostart -= delta
                oend -= delta
            count += 1
            if count >= COUNTLIMIT and not self.loop:
                break
        else:
            cont = 0
        
        if MEM_LEAK_TEST:
            win.EmptyUndoBuffer()
        
        if cont:
            if MEM_LEAK_TEST:
                scheduler.FutureCall(1, self.ReentrantReplace, (ostart, oend, ris, win))
            elif 1:
                wx.CallAfter(self.ReentrantReplace, (ostart, oend, ris, win))
            else:
                self._replace_again2((ostart, oend, ris, win))
        else:
            self.replacing = 0
            self.sel(ostart, oend, '', win)
            if self.root.control.GetPageCount() and \
               self.root.control.GetCurrentPage() == self.parent:
                win.SetFocus()
            if not MEM_LEAK_TEST:
                win.EndUndoAction()
    
    def _replace_again1(self, evt):
        self._replace_args, args = None, self._replace_args
        self.ReentrantReplace(args)
    
    def _replace_again2(self, args):
        self._replace_args = args
        self.replace_t.Start(1, wx.TIMER_ONE_SHOT)
    
    def OnReplaceAll(self, evt):
        global COUNTLIMIT
        if self.replacing:
            return
        COUNTLIMIT = OCOUNTLIMIT
        self.replaceAll(evt, 0)
    
    def OnReplaceSel(self, evt):
        if self.replacing:
            return
        self.replaceAll(evt, 1)
    
    def _simple_re_all(self, expression, template, flags=0):
        win = self.parent.GetWindow1()
        text = wx.stc.StyledTextCtrl.GetText(win)
        c = re.compile(expression, flags)
        win.SetText(c.sub(template, text))
    
    def _replace_re_all(self, expression, template, flags=0):
        win = self.parent.GetWindow1()
        text = wx.stc.StyledTextCtrl.GetText(win)
        c = re.compile(expression, flags)
        
        #need to implement the equivalent of...
        ## win.SetText(c.sub(template, text))
        
        lastpw = 0
        lastp = 0
        c = re.compile(expression, flags)
        try:
            _1, win.recording = win.recording, 0
            win.BeginUndoAction()
            try:
                for match in c.finditer(text):
                    start, end = match.span()
                    plain = match.group()
                    plainn = match.expand(template)
                    
                    plainl = len(plain.encode('utf-8'))
                    lastpw += len(text[lastp:start].encode('utf-8'))
                    
                    assert win.GetTextRange(lastpw, lastpw+plainl) == plain
                    
                    win.SetSelection(lastpw, lastpw+plainl)
                    win.ReplaceSelection(plainn)
                    plainnl = len(plainn.encode('utf-8'))
                    
                    assert win.GetTextRange(lastpw, lastpw+plainnl) == plainn
                    
                    lastpw += plainnl
                    lastp = end
            finally:
                win.EndUndoAction()
                win.recording = _1
        except:
            _1, win.recording = win.recording, 0
            win.Undo()
            win.recording = _1
            raise
    
    def _re_replace_again1(self, evt):
        self._re_replace_args, args = None, self._re_replace_args
        wx.CallAfter(self.ReentrantRegularExpressionReplace, (args,))
    
    def _re_replace_again2(self, args):
        self._re_replace_args = args
        self.replace_t2.Start(1, wx.TIMER_ONE_SHOT)
    
    def REreplaceAll(self, expression, template, flags=0):
        win = self.parent.GetWindow1()
        lastpw = 0
        c = re.compile(expression, flags)
        _1, win.recording = win.recording, 0

        wx.CallAfter(self.ReentrantRegularExpressionReplace, (lastpw, c, template, _1, win))
    
    def ReentrantRegularExpressionReplace(self, state):
        global COUNTLIMIT
        COUNTLIMIT = min(1000, int(COUNTLIMIT*1.5))
        lastpw, c, template, _1, win = state
        
        lastp = 0
        cont = 1
        
        text = win.GetTextRange(lastpw, win.GetTextLength())
        for i, match in enumerate(c.finditer(text)):
            start, end = match.span()
            plain = match.group()
            plainn = match.expand(template)
            
            plainl = len(plain.encode('utf-8'))
            lastpw += len(text[lastp:start].encode('utf-8'))
            
            assert win.GetTextRange(lastpw, lastpw+plainl) == plain
            
            win.SetSelection(lastpw, lastpw+plainl)
            win.ReplaceSelection(plainn)
            plainnl = len(plainn.encode('utf-8'))
            
            assert win.GetTextRange(lastpw, lastpw+plainnl) == plainn
            
            lastpw += plainnl
            lastp = end
            if i == COUNTLIMIT-1:
                break
        else:
            cont = 0
        
        if MEM_LEAK_TEST:
            win.EmptyUndoBuffer()
        
        if cont:
            if MEM_LEAK_TEST:
                wx.FutureCall(1, self.ReentrantRegularExpressionReplace, (lastpw, c, template, _1, win))
            elif 1:
                wx.CallAfter(self.ReentrantRegularExpressionReplace, (lastpw, c, template, _1, win))
            else:
                self._re_replace_again2((lastpw, c, template, _1, win))
        else:
            if not MEM_LEAK_TEST:
                win.EndUndoAction()
                win.recording = _1
                
    #----------------------------------

    def readPreferences(self):
        try:
            prefs = self.parent.GetWindow1().findbarprefs
        except:
            prefs = self.parent.GetWindow1().findbarprefs = {}
        # Set the defaults individually so that adding options works
        # as expected.
        prefs.setdefault('prefs_version', 1)
        prefs.setdefault('find', [])
        prefs.setdefault('replace', [])
        prefs.setdefault('case', 0)
        prefs.setdefault('wrap', 1)
        prefs.setdefault('smartcase', 0)
        #prefs.setdefault('regex', 0)
        #prefs.setdefault('multiline', 0)
        #prefs.setdefault('whole_word', 0)
        #prefs.setdefault('quoted', 0)
        #prefs.setdefault('commented', 0)

        self.preferences = prefs
        return prefs

    def savePreferences(self):
        def getlist(c):
            if not isinstance(c, wx.ComboBox):
                return []
            if self.root.getglobal('no_findbar_history'):
                return []
            cc = c.GetCount()
            e = [c.GetString(i) for i in xrange(cc)]
            e = [i for i in e if i]
            a = c.GetValue()
            if a:
                if a in e:
                    e.remove(a)
                e = [a] + e
            e = e[:10]
            ## if len(e) > cc:
                ## c.Append(e[-1])
            ## for i in xrange(len(e)):
                ## c.SetString(i, e[i])
            ## c.SetSelection(0)
            return e

        prefs = {
            'prefs_version': 1,
            'find': getlist(self.box1),
            'case': self.case.IsChecked(),
            'wrap': self.wrap.IsChecked(),
            #'regex': self.re.IsChecked(),
            #'multiline': self.multiline.IsChecked(),
            #'whole_word': self.ww.IsChecked(),
            #'quoted': self.quoted.IsChecked(),
            #'commented': self.commented.IsChecked(),
            }
        #if I am a replace bar, save the smartcase replacement option.
        if not isinstance(self, FindBar):
            prefs['replace'] = getlist(self.box2)
            prefs['smartcase'] = self.smartcase.IsChecked()
        
        self.parent.GetWindow1().findbarprefs.update(prefs)

#-----------------------------------------------------------------------------

class FindBar(ReplaceBar):
    """
    Embedded find in the current document
    """

USE_MINI_CHECKBOXES = 0
DOUBLE_ROW_ONE = 0
USE_BOX_SIZERS = 1

if __name__ == "__main__":
    ## Test Code to mess with layout
    # some dummy classes for prefs, etc.
    class Window1:
        findbarprefs = {}

    class root:
        def getglobal(self, key):
            return {}

    class TestFrame(wx.Frame):
        def __init__(self, *args, **kwargs):
            wx.Frame.__init__(self, *args, **kwargs)
            
            sizer = wx.BoxSizer(wx.VERTICAL)
            fb = FindBar(self, root())
            rb = ReplaceBar(self, root())
            
            sizer.Add(fb, 0, wx.EXPAND)
            sizer.Add((20,20))
            sizer.Add(rb, 0, wx.EXPAND)
            
            self.SetSizerAndFit(sizer)
            
        def GetWindow1(self):
            return Window1()

    app = wx.App(False)
           
    f = TestFrame(None)

    f.Show()
    wx.CallAfter(f.SendSizeEvent)
    app.MainLoop()
