blob: b90daba1e9a7a252b303d9bb172a548b3f4b31c4 [file] [log] [blame]
Terry Jan Reedy9946a282013-08-18 18:22:34 -04001'''Define SearchDialogBase used by Search, Replace, and Grep dialogs.'''
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -04002
3from Tkinter import (Toplevel, Frame, Entry, Label, Button,
4 Checkbutton, Radiobutton)
David Scherer7aced172000-08-15 01:13:23 +00005
6class SearchDialogBase:
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -04007 '''Create most of a 3 or 4 row, 3 column search dialog.
Terry Jan Reedy9946a282013-08-18 18:22:34 -04008
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -04009 The left and wide middle column contain:
10 1 or 2 labeled text entry lines (make_entry, create_entries);
11 a row of standard Checkbuttons (make_frame, create_option_buttons),
12 each of which corresponds to a search engine Variable;
13 a row of dialog-specific Check/Radiobuttons (create_other_buttons).
Terry Jan Reedya81e9692013-08-18 18:27:02 -040014
Terry Jan Reedy9946a282013-08-18 18:22:34 -040015 The narrow right column contains command buttons
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040016 (make_button, create_command_buttons).
Terry Jan Reedy9946a282013-08-18 18:22:34 -040017 These are bound to functions that execute the command.
18
19 Except for command buttons, this base class is not limited to
20 items common to all three subclasses. Rather, it is the Find dialog
21 minus the "Find Next" command and its execution function.
22 The other dialogs override methods to replace and add widgets.
23 '''
David Scherer7aced172000-08-15 01:13:23 +000024
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040025 title = "Search Dialog" # replace in subclasses
David Scherer7aced172000-08-15 01:13:23 +000026 icon = "Search"
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040027 needwrapbutton = 1 # not in Find in Files
David Scherer7aced172000-08-15 01:13:23 +000028
29 def __init__(self, root, engine):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040030 '''Initialize root, engine, and top attributes.
31
32 top (level widget): set in create_widgets() called from open().
33 text (Text being searched): set in open(), only used in subclasses().
34 ent (ry): created in make_entry() called from create_entry().
35 row (of grid): 0 in create_widgets(), +1 in make_entry/frame().
36
37 title (of dialog): class attribute, override in subclasses.
38 icon (of dialog): ditto, use unclear if cannot minimize dialog.
39 '''
David Scherer7aced172000-08-15 01:13:23 +000040 self.root = root
41 self.engine = engine
42 self.top = None
43
Chui Tey5a231c82002-11-06 02:18:45 +000044 def open(self, text, searchphrase=None):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040045 "Make dialog visible on top of others and ready to use."
David Scherer7aced172000-08-15 01:13:23 +000046 self.text = text
47 if not self.top:
48 self.create_widgets()
49 else:
50 self.top.deiconify()
51 self.top.tkraise()
Chui Tey5a231c82002-11-06 02:18:45 +000052 if searchphrase:
53 self.ent.delete(0,"end")
54 self.ent.insert("end",searchphrase)
David Scherer7aced172000-08-15 01:13:23 +000055 self.ent.focus_set()
56 self.ent.selection_range(0, "end")
57 self.ent.icursor(0)
58 self.top.grab_set()
59
60 def close(self, event=None):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040061 "Put dialog away for later use."
David Scherer7aced172000-08-15 01:13:23 +000062 if self.top:
63 self.top.grab_release()
64 self.top.withdraw()
65
66 def create_widgets(self):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040067 '''Create basic 3 row x 3 col search (find) dialog.
68
69 Other dialogs override subsidiary create_x methods as needed.
70 Replace and Find-in-Files add another entry row.
71 '''
David Scherer7aced172000-08-15 01:13:23 +000072 top = Toplevel(self.root)
73 top.bind("<Return>", self.default_command)
74 top.bind("<Escape>", self.close)
75 top.protocol("WM_DELETE_WINDOW", self.close)
76 top.wm_title(self.title)
77 top.wm_iconname(self.icon)
78 self.top = top
79
80 self.row = 0
Chui Tey72a8a3b2002-11-04 23:07:51 +000081 self.top.grid_columnconfigure(0, pad=2, weight=0)
82 self.top.grid_columnconfigure(1, pad=2, minsize=100, weight=100)
David Scherer7aced172000-08-15 01:13:23 +000083
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040084 self.create_entries() # row 0 (and maybe 1), cols 0, 1
85 self.create_option_buttons() # next row, cols 0, 1
86 self.create_other_buttons() # next row, cols 0, 1
87 self.create_command_buttons() # col 2, all rows
David Scherer7aced172000-08-15 01:13:23 +000088
89 def make_entry(self, label, var):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040090 "Return gridded labeled Entry."
David Scherer7aced172000-08-15 01:13:23 +000091 l = Label(self.top, text=label)
Kurt B. Kaiser4fc90472002-11-21 03:02:17 +000092 l.grid(row=self.row, column=0, sticky="nw")
David Scherer7aced172000-08-15 01:13:23 +000093 e = Entry(self.top, textvariable=var, exportselection=0)
Kurt B. Kaiser4fc90472002-11-21 03:02:17 +000094 e.grid(row=self.row, column=1, sticky="nwe")
David Scherer7aced172000-08-15 01:13:23 +000095 self.row = self.row + 1
96 return e
97
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -040098 def create_entries(self):
99 "Create one or more entry lines with make_entry."
100 self.ent = self.make_entry("Find:", self.engine.patvar)
101
Chui Tey72a8a3b2002-11-04 23:07:51 +0000102 def make_frame(self,labeltext=None):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -0400103 "Return gridded labeled Frame for option or other buttons."
Chui Tey72a8a3b2002-11-04 23:07:51 +0000104 if labeltext:
105 l = Label(self.top, text=labeltext)
Kurt B. Kaiser4fc90472002-11-21 03:02:17 +0000106 l.grid(row=self.row, column=0, sticky="nw")
David Scherer7aced172000-08-15 01:13:23 +0000107 f = Frame(self.top)
Kurt B. Kaiser4fc90472002-11-21 03:02:17 +0000108 f.grid(row=self.row, column=1, columnspan=1, sticky="nwe")
David Scherer7aced172000-08-15 01:13:23 +0000109 self.row = self.row + 1
110 return f
111
David Scherer7aced172000-08-15 01:13:23 +0000112 def create_option_buttons(self):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -0400113 "Fill frame with Checkbuttons bound to SearchEngine booleanvars."
Chui Tey72a8a3b2002-11-04 23:07:51 +0000114 f = self.make_frame("Options")
David Scherer7aced172000-08-15 01:13:23 +0000115
116 btn = Checkbutton(f, anchor="w",
117 variable=self.engine.revar,
118 text="Regular expression")
119 btn.pack(side="left", fill="both")
120 if self.engine.isre():
121 btn.select()
122
123 btn = Checkbutton(f, anchor="w",
124 variable=self.engine.casevar,
125 text="Match case")
126 btn.pack(side="left", fill="both")
127 if self.engine.iscase():
128 btn.select()
129
130 btn = Checkbutton(f, anchor="w",
131 variable=self.engine.wordvar,
132 text="Whole word")
133 btn.pack(side="left", fill="both")
134 if self.engine.isword():
135 btn.select()
136
137 if self.needwrapbutton:
138 btn = Checkbutton(f, anchor="w",
139 variable=self.engine.wrapvar,
140 text="Wrap around")
141 btn.pack(side="left", fill="both")
142 if self.engine.iswrap():
143 btn.select()
144
145 def create_other_buttons(self):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -0400146 "Fill frame with buttons tied to other options."
Chui Tey72a8a3b2002-11-04 23:07:51 +0000147 f = self.make_frame("Direction")
David Scherer7aced172000-08-15 01:13:23 +0000148
David Scherer7aced172000-08-15 01:13:23 +0000149 btn = Radiobutton(f, anchor="w",
150 variable=self.engine.backvar, value=1,
151 text="Up")
152 btn.pack(side="left", fill="both")
153 if self.engine.isback():
154 btn.select()
155
156 btn = Radiobutton(f, anchor="w",
157 variable=self.engine.backvar, value=0,
158 text="Down")
159 btn.pack(side="left", fill="both")
160 if not self.engine.isback():
161 btn.select()
162
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -0400163 def make_button(self, label, command, isdef=0):
164 "Return command button gridded in command frame."
165 b = Button(self.buttonframe,
166 text=label, command=command,
167 default=isdef and "active" or "normal")
168 cols,rows=self.buttonframe.grid_size()
169 b.grid(pady=1,row=rows,column=0,sticky="ew")
170 self.buttonframe.grid(rowspan=rows+1)
171 return b
172
David Scherer7aced172000-08-15 01:13:23 +0000173 def create_command_buttons(self):
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -0400174 "Place buttons in vertical command frame gridded on right."
Chui Tey72a8a3b2002-11-04 23:07:51 +0000175 f = self.buttonframe = Frame(self.top)
Kurt B. Kaiser4fc90472002-11-21 03:02:17 +0000176 f.grid(row=0,column=2,padx=2,pady=2,ipadx=2,ipady=2)
Chui Tey72a8a3b2002-11-04 23:07:51 +0000177
178 b = self.make_button("close", self.close)
David Scherer7aced172000-08-15 01:13:23 +0000179 b.lower()
Terry Jan Reedyaa608fd2014-06-26 01:40:46 -0400180
181if __name__ == '__main__':
182 import unittest
183 unittest.main(
184 'idlelib.idle_test.test_searchdialogbase', verbosity=2)