1from tkinter import TclError
2
3from idlelib import searchengine
4from idlelib.searchbase import SearchDialogBase
5
6def _setup(text):
7    "Create or find the singleton SearchDialog instance."
8    root = text._root()
9    engine = searchengine.get(root)
10    if not hasattr(engine, "_searchdialog"):
11        engine._searchdialog = SearchDialog(root, engine)
12    return engine._searchdialog
13
14def find(text):
15    "Handle the editor edit menu item and corresponding event."
16    pat = text.get("sel.first", "sel.last")
17    return _setup(text).open(text, pat)  # Open is inherited from SDBase.
18
19def find_again(text):
20    "Handle the editor edit menu item and corresponding event."
21    return _setup(text).find_again(text)
22
23def find_selection(text):
24    "Handle the editor edit menu item and corresponding event."
25    return _setup(text).find_selection(text)
26
27
28class SearchDialog(SearchDialogBase):
29
30    def create_widgets(self):
31        SearchDialogBase.create_widgets(self)
32        self.make_button("Find Next", self.default_command, 1)
33
34    def default_command(self, event=None):
35        if not self.engine.getprog():
36            return
37        self.find_again(self.text)
38
39    def find_again(self, text):
40        if not self.engine.getpat():
41            self.open(text)
42            return False
43        if not self.engine.getprog():
44            return False
45        res = self.engine.search_text(text)
46        if res:
47            line, m = res
48            i, j = m.span()
49            first = "%d.%d" % (line, i)
50            last = "%d.%d" % (line, j)
51            try:
52                selfirst = text.index("sel.first")
53                sellast = text.index("sel.last")
54                if selfirst == first and sellast == last:
55                    self.bell()
56                    return False
57            except TclError:
58                pass
59            text.tag_remove("sel", "1.0", "end")
60            text.tag_add("sel", first, last)
61            text.mark_set("insert", self.engine.isback() and first or last)
62            text.see("insert")
63            return True
64        else:
65            self.bell()
66            return False
67
68    def find_selection(self, text):
69        pat = text.get("sel.first", "sel.last")
70        if pat:
71            self.engine.setcookedpat(pat)
72        return self.find_again(text)
73
74
75def _search_dialog(parent):  # htest #
76    "Display search test box."
77    from tkinter import Toplevel, Text
78    from tkinter.ttk import Button
79
80    box = Toplevel(parent)
81    box.title("Test SearchDialog")
82    x, y = map(int, parent.geometry().split('+')[1:])
83    box.geometry("+%d+%d" % (x, y + 175))
84    text = Text(box, inactiveselectbackground='gray')
85    text.pack()
86    text.insert("insert","This is a sample string.\n"*5)
87
88    def show_find():
89        text.tag_add('sel', '1.0', 'end')
90        _setup(text).open(text)
91        text.tag_remove('sel', '1.0', 'end')
92
93    button = Button(box, text="Search (selection ignored)", command=show_find)
94    button.pack()
95
96if __name__ == '__main__':
97    import unittest
98    unittest.main('idlelib.idle_test.test_search',
99                  verbosity=2, exit=False)
100
101    from idlelib.idle_test.htest import run
102    run(_search_dialog)
103