@@ -1,6 +1,8 @@
11importos
22importunittest
3+importtkinter
34fromtkinterimportfiledialog
5+fromtkinterimportttk
46fromtkinter.commondialogimportDialog
57fromtest.supportimportrequires, swap_attr
68fromtest.test_tkinter.supportimportsetUpModule# noqa: F401
@@ -101,6 +103,104 @@ def test_subclasses(self):
101103self.assertIsInstance(d, filedialog.FileDialog)
102104self.assertEqual(d.top.title(), cls.title)
103105106+# --- Themed widgets and keyboard (modernization) ---
107+108+defopen(self, **kw):
109+d=filedialog.FileDialog(self.root, **kw)
110+self.addCleanup(lambda: d.top.winfo_exists() andd.top.destroy())
111+d.top.deiconify() # __init__ leaves the dialog withdrawn until go()
112+d.top.update()
113+returnd
114+115+deftest_use_ttk(self):
116+# The dialog uses the themed (ttk) widgets by default.
117+d=self.open()
118+self.assertEqual(d.ok_button.winfo_class(), 'TButton')
119+self.assertEqual(d.selection.winfo_class(), 'TEntry')
120+121+deftest_use_classic(self):
122+# use_ttk=False uses the classic Tk widgets.
123+d=self.open(use_ttk=False)
124+self.assertEqual(d.ok_button.winfo_class(), 'Button')
125+self.assertEqual(d.selection.winfo_class(), 'Entry')
126+ifd.top._windowingsystem=='x11':
127+self.assertEqual(str(d.botframe.cget('relief')), 'raised')
128+129+deftest_background(self):
130+# The ttk dialog adopts the ttk background, even a customized one, while
131+# the classic dialog keeps the default Toplevel background.
132+style=ttk.Style(self.root)
133+old=style.lookup('.', 'background')
134+style.configure('.', background='#123456')
135+self.addCleanup(style.configure, '.', background=old)
136+d=self.open()
137+self.assertEqual(str(d.top.cget('background')), '#123456')
138+d=self.open(use_ttk=False)
139+ref=tkinter.Toplevel(self.root)
140+self.addCleanup(ref.destroy)
141+self.assertEqual(str(d.top.cget('background')),
142+str(ref.cget('background')))
143+144+deftest_button_accelerator(self):
145+# The buttons' "&" accelerators are parsed.
146+d=self.open()
147+self.assertEqual(str(d.ok_button.cget('text')), 'OK')
148+self.assertEqual(int(d.ok_button.cget('underline')), 0)
149+150+deftest_default_ring(self):
151+# The default ring follows the keyboard focus among the buttons.
152+d=self.open()
153+self.assertEqual(str(d.cancel_button.cget('default')), 'normal')
154+d.cancel_button.focus_force()
155+d.top.update()
156+self.assertEqual(str(d.cancel_button.cget('default')), 'active')
157+d.ok_button.focus_force()
158+d.top.update()
159+self.assertEqual(str(d.cancel_button.cget('default')), 'normal')
160+161+deftest_alt_key(self):
162+# Alt + the underlined letter invokes the matching button.
163+d=self.open()
164+invoked= []
165+d.cancel_button.configure(command=lambda: invoked.append(True))
166+d.top.focus_force()
167+d.top.update()
168+d.top.event_generate('<Alt-c>') # "&Cancel"
169+d.top.update()
170+self.assertTrue(invoked)
171+172+deftest_escape_cancels(self):
173+# The Escape key cancels the dialog.
174+d=self.open()
175+d.how='spam'
176+d.top.focus_force()
177+d.top.update()
178+d.top.event_generate('<Escape>')
179+d.top.update()
180+self.assertIsNone(d.how)
181+182+deftest_horizontal_scrollbars(self):
183+# Each list has a horizontal scrollbar besides the vertical one.
184+d=self.open()
185+self.assertEqual(str(d.dirshbar.cget('orient')), 'horizontal')
186+self.assertEqual(str(d.fileshbar.cget('orient')), 'horizontal')
187+self.assertTrue(d.dirs.cget('xscrollcommand'))
188+self.assertTrue(d.files.cget('xscrollcommand'))
189+190+deftest_type_ahead(self):
191+# Typing characters over a list jumps to a matching entry.
192+d=self.open()
193+d.directory=os.getcwd() # browsing the match fills the selection entry
194+d.files.delete(0, 'end')
195+fornamein ('alpha', 'bravo', 'charlie'):
196+d.files.insert('end', name)
197+d.files.focus_force()
198+d.top.update()
199+d.files.event_generate('<Key>', keysym='c')
200+d.top.update()
201+sel=d.files.curselection()
202+self.assertEqual([d.files.get(i) foriinsel], ['charlie'])
203+104204105205if__name__=="__main__":
106206unittest.main()