1'''Define SearchDialogBase used by Search, Replace, and Grep dialogs.''' 2 3from Tkinter import (Toplevel, Frame, Entry, Label, Button, 4 Checkbutton, Radiobutton) 5 6class SearchDialogBase: 7 '''Create most of a 3 or 4 row, 3 column search dialog. 8 9 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). 14 15 The narrow right column contains command buttons 16 (make_button, create_command_buttons). 17 These are bound to functions that execute the command. 18 19 Except for command buttons, this base class is not limited to items 20 common to all three subclasses. Rather, it is the Find dialog minus 21 the "Find Next" command, its execution function, and the 22 default_command attribute needed in create_widgets. The other 23 dialogs override attributes and methods, the latter to replace and 24 add widgets. 25 ''' 26 27 title = "Search Dialog" # replace in subclasses 28 icon = "Search" 29 needwrapbutton = 1 # not in Find in Files 30 31 def __init__(self, root, engine): 32 '''Initialize root, engine, and top attributes. 33 34 top (level widget): set in create_widgets() called from open(). 35 text (Text searched): set in open(), only used in subclasses(). 36 ent (ry): created in make_entry() called from create_entry(). 37 row (of grid): 0 in create_widgets(), +1 in make_entry/frame(). 38 default_command: set in subclasses, used in create_widgers(). 39 40 title (of dialog): class attribute, override in subclasses. 41 icon (of dialog): ditto, use unclear if cannot minimize dialog. 42 ''' 43 self.root = root 44 self.engine = engine 45 self.top = None 46 47 def open(self, text, searchphrase=None): 48 "Make dialog visible on top of others and ready to use." 49 self.text = text 50 if not self.top: 51 self.create_widgets() 52 else: 53 self.top.deiconify() 54 self.top.tkraise() 55 if searchphrase: 56 self.ent.delete(0,"end") 57 self.ent.insert("end",searchphrase) 58 self.ent.focus_set() 59 self.ent.selection_range(0, "end") 60 self.ent.icursor(0) 61 self.top.grab_set() 62 63 def close(self, event=None): 64 "Put dialog away for later use." 65 if self.top: 66 self.top.grab_release() 67 self.top.withdraw() 68 69 def create_widgets(self): 70 '''Create basic 3 row x 3 col search (find) dialog. 71 72 Other dialogs override subsidiary create_x methods as needed. 73 Replace and Find-in-Files add another entry row. 74 ''' 75 top = Toplevel(self.root) 76 top.bind("<Return>", self.default_command) 77 top.bind("<Escape>", self.close) 78 top.protocol("WM_DELETE_WINDOW", self.close) 79 top.wm_title(self.title) 80 top.wm_iconname(self.icon) 81 self.top = top 82 83 self.row = 0 84 self.top.grid_columnconfigure(0, pad=2, weight=0) 85 self.top.grid_columnconfigure(1, pad=2, minsize=100, weight=100) 86 87 self.create_entries() # row 0 (and maybe 1), cols 0, 1 88 self.create_option_buttons() # next row, cols 0, 1 89 self.create_other_buttons() # next row, cols 0, 1 90 self.create_command_buttons() # col 2, all rows 91 92 def make_entry(self, label_text, var): 93 '''Return (entry, label), . 94 95 entry - gridded labeled Entry for text entry. 96 label - Label widget, returned for testing. 97 ''' 98 label = Label(self.top, text=label_text) 99 label.grid(row=self.row, column=0, sticky="nw") 100 entry = Entry(self.top, textvariable=var, exportselection=0) 101 entry.grid(row=self.row, column=1, sticky="nwe") 102 self.row = self.row + 1 103 return entry, label 104 105 def create_entries(self): 106 "Create one or more entry lines with make_entry." 107 self.ent = self.make_entry("Find:", self.engine.patvar)[0] 108 109 def make_frame(self,labeltext=None): 110 '''Return (frame, label). 111 112 frame - gridded labeled Frame for option or other buttons. 113 label - Label widget, returned for testing. 114 ''' 115 if labeltext: 116 label = Label(self.top, text=labeltext) 117 label.grid(row=self.row, column=0, sticky="nw") 118 else: 119 label = '' 120 frame = Frame(self.top) 121 frame.grid(row=self.row, column=1, columnspan=1, sticky="nwe") 122 self.row = self.row + 1 123 return frame, label 124 125 def create_option_buttons(self): 126 '''Return (filled frame, options) for testing. 127 128 Options is a list of SearchEngine booleanvar, label pairs. 129 A gridded frame from make_frame is filled with a Checkbutton 130 for each pair, bound to the var, with the corresponding label. 131 ''' 132 frame = self.make_frame("Options")[0] 133 engine = self.engine 134 options = [(engine.revar, "Regular expression"), 135 (engine.casevar, "Match case"), 136 (engine.wordvar, "Whole word")] 137 if self.needwrapbutton: 138 options.append((engine.wrapvar, "Wrap around")) 139 for var, label in options: 140 btn = Checkbutton(frame, anchor="w", variable=var, text=label) 141 btn.pack(side="left", fill="both") 142 if var.get(): 143 btn.select() 144 return frame, options 145 146 def create_other_buttons(self): 147 '''Return (frame, others) for testing. 148 149 Others is a list of value, label pairs. 150 A gridded frame from make_frame is filled with radio buttons. 151 ''' 152 frame = self.make_frame("Direction")[0] 153 var = self.engine.backvar 154 others = [(1, 'Up'), (0, 'Down')] 155 for val, label in others: 156 btn = Radiobutton(frame, anchor="w", 157 variable=var, value=val, text=label) 158 btn.pack(side="left", fill="both") 159 if var.get() == val: 160 btn.select() 161 return frame, others 162 163 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 173 def create_command_buttons(self): 174 "Place buttons in vertical command frame gridded on right." 175 f = self.buttonframe = Frame(self.top) 176 f.grid(row=0,column=2,padx=2,pady=2,ipadx=2,ipady=2) 177 178 b = self.make_button("close", self.close) 179 b.lower() 180 181if __name__ == '__main__': 182 import unittest 183 unittest.main( 184 'idlelib.idle_test.test_searchdialogbase', verbosity=2) 185