]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/filebrowsebutton.py
Fixed problem with incorrect panel background on OS X.
[wxWidgets.git] / wxPython / wx / lib / filebrowsebutton.py
1 #----------------------------------------------------------------------
2 # Name: wxPython.lib.filebrowsebutton
3 # Purpose: Composite controls that provide a Browse button next to
4 # either a wxTextCtrl or a wxComboBox. The Browse button
5 # launches a wxFileDialog and loads the result into the
6 # other control.
7 #
8 # Author: Mike Fletcher
9 #
10 # RCS-ID: $Id$
11 # Copyright: (c) 2000 by Total Control Software
12 # Licence: wxWindows license
13 #----------------------------------------------------------------------
14 # 12/02/2003 - Jeff Grimmett (grimmtooth@softhome.net)
15 #
16 # o 2.5 Compatability changes
17 #
18
19 import os
20 import types
21
22 import wx
23
24 #----------------------------------------------------------------------
25
26 class FileBrowseButton(wx.Panel):
27 """
28 A control to allow the user to type in a filename or browse with
29 the standard file dialog to select file
30 """
31 def __init__ (self, parent, id= -1,
32 pos = wx.DefaultPosition,
33 size = wx.DefaultSize,
34 style = wx.TAB_TRAVERSAL,
35 labelText= "File Entry:",
36 buttonText= "Browse",
37 toolTip= "Type filename or click browse to choose file",
38 # following are the values for a file dialog box
39 dialogTitle = "Choose a file",
40 startDirectory = ".",
41 initialValue = "",
42 fileMask = "*.*",
43 fileMode = wx.OPEN,
44 # callback for when value changes (optional)
45 changeCallback= lambda x:x
46 ):
47 """
48 :param labelText: Text for label to left of text field
49 :param buttonText: Text for button which launches the file dialog
50 :param toolTip: Help text
51 :param dialogTitle: Title used in file dialog
52 :param startDirectory: Default directory for file dialog startup
53 :param fileMask: File mask (glob pattern, such as *.*) to use in file dialog
54 :param fileMode: wx.OPEN or wx.SAVE, indicates type of file dialog to use
55 :param changeCallback: Optional callback called for all changes in value of the control
56 """
57
58 # store variables
59 self.labelText = labelText
60 self.buttonText = buttonText
61 self.toolTip = toolTip
62 self.dialogTitle = dialogTitle
63 self.startDirectory = startDirectory
64 self.initialValue = initialValue
65 self.fileMask = fileMask
66 self.fileMode = fileMode
67 self.changeCallback = changeCallback
68 self.callCallback = True
69
70
71 # get background to match it
72 try:
73 self._bc = parent.GetBackgroundColour()
74 except:
75 pass
76
77 # create the dialog
78 self.createDialog(parent, id, pos, size, style )
79 # Setting a value causes the changeCallback to be called.
80 # In this case that would be before the return of the
81 # constructor. Not good. So a default value on
82 # SetValue is used to disable the callback
83 self.SetValue( initialValue, 0)
84
85
86 def createDialog( self, parent, id, pos, size, style ):
87 """Setup the graphic representation of the dialog"""
88 wx.Panel.__init__ (self, parent, id, pos, size, style)
89 self.SetMinSize(size) # play nice with sizers
90
91 # try to set the background colour
92 try:
93 #Question: is this still needed on other platforms?
94 #It should have transparent background on Mac
95 if wx.Platform != "__WXMAC__":
96 self.SetBackgroundColour(self._bc)
97 except:
98 pass
99
100 box = wx.BoxSizer(wx.HORIZONTAL)
101
102 self.label = self.createLabel( )
103 box.Add( self.label, 0, wx.CENTER )
104
105 self.textControl = self.createTextControl()
106 box.Add( self.textControl, 1, wx.LEFT|wx.CENTER, 5)
107
108 self.browseButton = self.createBrowseButton()
109 box.Add( self.browseButton, 0, wx.LEFT|wx.CENTER, 5)
110
111 # add a border around the whole thing and resize the panel to fit
112 outsidebox = wx.BoxSizer(wx.VERTICAL)
113 outsidebox.Add(box, 1, wx.EXPAND|wx.ALL, 3)
114 outsidebox.Fit(self)
115
116 self.SetAutoLayout(True)
117 self.SetSizer( outsidebox )
118 self.Layout()
119 if type( size ) == types.TupleType:
120 size = apply( wx.Size, size)
121 self.SetDimensions(-1, -1, size.width, size.height, wx.SIZE_USE_EXISTING)
122
123 # if size.width != -1 or size.height != -1:
124 # self.SetSize(size)
125
126 def SetBackgroundColour(self,color):
127 wx.Panel.SetBackgroundColour(self,color)
128 self.label.SetBackgroundColour(color)
129
130 def createLabel( self ):
131 """Create the label/caption"""
132 label = wx.StaticText(self, -1, self.labelText, style =wx.ALIGN_RIGHT )
133 font = label.GetFont()
134 w, h, d, e = self.GetFullTextExtent(self.labelText, font)
135 label.SetSize((w+5, h))
136 return label
137
138 def createTextControl( self):
139 """Create the text control"""
140 textControl = wx.TextCtrl(self, -1)
141 textControl.SetToolTipString( self.toolTip )
142 if self.changeCallback:
143 textControl.Bind(wx.EVT_TEXT, self.OnChanged)
144 textControl.Bind(wx.EVT_COMBOBOX, self.OnChanged)
145 return textControl
146
147 def OnChanged(self, evt):
148 if self.callCallback and self.changeCallback:
149 self.changeCallback(evt)
150
151 def createBrowseButton( self):
152 """Create the browse-button control"""
153 button =wx.Button(self, -1, self.buttonText)
154 button.SetToolTipString( self.toolTip )
155 button.Bind(wx.EVT_BUTTON, self.OnBrowse)
156 return button
157
158
159 def OnBrowse (self, event = None):
160 """ Going to browse for file... """
161 current = self.GetValue()
162 directory = os.path.split(current)
163 if os.path.isdir( current):
164 directory = current
165 current = ''
166 elif directory and os.path.isdir( directory[0] ):
167 current = directory[1]
168 directory = directory [0]
169 else:
170 directory = self.startDirectory
171 dlg = wx.FileDialog(self, self.dialogTitle, directory, current,
172 self.fileMask, self.fileMode)
173
174 if dlg.ShowModal() == wx.ID_OK:
175 self.SetValue(dlg.GetPath())
176 dlg.Destroy()
177
178
179 def GetValue (self):
180 """
181 retrieve current value of text control
182 """
183 return self.textControl.GetValue()
184
185 def SetValue (self, value, callBack=1):
186 """set current value of text control"""
187 save = self.callCallback
188 self.callCallback = callBack
189 self.textControl.SetValue(value)
190 self.callCallback = save
191
192
193 def Enable (self, value):
194 """ Convenient enabling/disabling of entire control """
195 self.label.Enable (value)
196 self.textControl.Enable (value)
197 return self.browseButton.Enable (value)
198
199 def GetLabel( self ):
200 """ Retrieve the label's current text """
201 return self.label.GetLabel()
202
203 def SetLabel( self, value ):
204 """ Set the label's current text """
205 rvalue = self.label.SetLabel( value )
206 self.Refresh( True )
207 return rvalue
208
209
210
211
212 class FileBrowseButtonWithHistory( FileBrowseButton ):
213 """
214 with following additions:
215 __init__(..., history=None)
216
217 history -- optional list of paths for initial history drop-down
218 (must be passed by name, not a positional argument)
219 If history is callable it will must return a list used
220 for the history drop-down
221
222 changeCallback -- as for FileBrowseButton, but with a work-around
223 for win32 systems which don't appear to create wx.EVT_COMBOBOX
224 events properly. There is a (slight) chance that this work-around
225 will cause some systems to create two events for each Combobox
226 selection. If you discover this condition, please report it!
227
228 As for a FileBrowseButton.__init__ otherwise.
229
230 GetHistoryControl()
231 Return reference to the control which implements interfaces
232 required for manipulating the history list. See GetHistoryControl
233 documentation for description of what that interface is.
234
235 GetHistory()
236 Return current history list
237
238 SetHistory( value=(), selectionIndex = None )
239 Set current history list, if selectionIndex is not None, select that index
240
241 """
242 def __init__( self, *arguments, **namedarguments):
243 self.history = namedarguments.get( "history" )
244 if self.history:
245 del namedarguments["history"]
246
247 self.historyCallBack=None
248 if callable(self.history):
249 self.historyCallBack=self.history
250 self.history=None
251 apply( FileBrowseButton.__init__, ( self,)+arguments, namedarguments)
252
253
254 def createTextControl( self):
255 """Create the text control"""
256 textControl = wx.ComboBox(self, -1, style = wx.CB_DROPDOWN )
257 textControl.SetToolTipString( self.toolTip )
258 textControl.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
259 if self.changeCallback:
260 textControl.Bind(wx.EVT_TEXT, self.changeCallback)
261 textControl.Bind(wx.EVT_COMBOBOX, self.changeCallback)
262 if self.history:
263 history=self.history
264 self.history=None
265 self.SetHistory( history, control=textControl)
266 return textControl
267
268
269 def GetHistoryControl( self ):
270 """
271 Return a pointer to the control which provides (at least)
272 the following methods for manipulating the history list:
273
274 Append( item ) -- add item
275 Clear() -- clear all items
276 Delete( index ) -- 0-based index to delete from list
277 SetSelection( index ) -- 0-based index to select in list
278
279 Semantics of the methods follow those for the wxComboBox control
280 """
281 return self.textControl
282
283
284 def SetHistory( self, value=(), selectionIndex = None, control=None ):
285 """Set the current history list"""
286 if control is None:
287 control = self.GetHistoryControl()
288 if self.history == value:
289 return
290 self.history = value
291 # Clear history values not the selected one.
292 tempValue=control.GetValue()
293 # clear previous values
294 control.Clear()
295 control.SetValue(tempValue)
296 # walk through, appending new values
297 for path in value:
298 control.Append( path )
299 if selectionIndex is not None:
300 control.SetSelection( selectionIndex )
301
302
303 def GetHistory( self ):
304 """Return the current history list"""
305 if self.historyCallBack != None:
306 return self.historyCallBack()
307 else:
308 return list( self.history )
309
310
311 def OnSetFocus(self, event):
312 """When the history scroll is selected, update the history"""
313 if self.historyCallBack != None:
314 self.SetHistory( self.historyCallBack(), control=self.textControl)
315 event.Skip()
316
317
318 if wx.Platform == "__WXMSW__":
319 def SetValue (self, value, callBack=1):
320 """ Convenient setting of text control value, works
321 around limitation of wx.ComboBox """
322 save = self.callCallback
323 self.callCallback = callBack
324 self.textControl.SetValue(value)
325 self.callCallback = save
326
327 # Hack to call an event handler
328 class LocalEvent:
329 def __init__(self, string):
330 self._string=string
331 def GetString(self):
332 return self._string
333 if callBack==1:
334 # The callback wasn't being called when SetValue was used ??
335 # So added this explicit call to it
336 self.changeCallback(LocalEvent(value))
337
338
339 class DirBrowseButton(FileBrowseButton):
340 def __init__(self, parent, id = -1,
341 pos = wx.DefaultPosition, size = wx.DefaultSize,
342 style = wx.TAB_TRAVERSAL,
343 labelText = 'Select a directory:',
344 buttonText = 'Browse',
345 toolTip = 'Type directory name or browse to select',
346 dialogTitle = '',
347 startDirectory = '.',
348 changeCallback = None,
349 dialogClass = wx.DirDialog):
350 FileBrowseButton.__init__(self, parent, id, pos, size, style,
351 labelText, buttonText, toolTip,
352 dialogTitle, startDirectory,
353 changeCallback = changeCallback)
354 self.dialogClass = dialogClass
355 #
356
357 def OnBrowse(self, ev = None):
358 dialog = self.dialogClass(self,
359 message = self.dialogTitle,
360 defaultPath = self.startDirectory)
361 if dialog.ShowModal() == wx.ID_OK:
362 self.SetValue(dialog.GetPath())
363 dialog.Destroy()
364 #
365
366
367 #----------------------------------------------------------------------
368
369
370 if __name__ == "__main__":
371 #from skeletonbuilder import rulesfile
372 class SimpleCallback:
373 def __init__( self, tag ):
374 self.tag = tag
375 def __call__( self, event ):
376 print self.tag, event.GetString()
377 class DemoFrame( wx.Frame ):
378 def __init__(self, parent):
379 wx.Frame.__init__(self, parent, -1, "File entry with browse", size=(500,260))
380 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
381 panel = wx.Panel (self,-1)
382 innerbox = wx.BoxSizer(wx.VERTICAL)
383 control = FileBrowseButton(
384 panel,
385 initialValue = "z:\\temp",
386 )
387 innerbox.Add( control, 0, wx.EXPAND )
388 middlecontrol = FileBrowseButtonWithHistory(
389 panel,
390 labelText = "With History",
391 initialValue = "d:\\temp",
392 history = ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
393 changeCallback= SimpleCallback( "With History" ),
394 )
395 innerbox.Add( middlecontrol, 0, wx.EXPAND )
396 middlecontrol = FileBrowseButtonWithHistory(
397 panel,
398 labelText = "History callback",
399 initialValue = "d:\\temp",
400 history = self.historyCallBack,
401 changeCallback= SimpleCallback( "History callback" ),
402 )
403 innerbox.Add( middlecontrol, 0, wx.EXPAND )
404 self.bottomcontrol = control = FileBrowseButton(
405 panel,
406 labelText = "With Callback",
407 style = wx.SUNKEN_BORDER|wx.CLIP_CHILDREN ,
408 changeCallback= SimpleCallback( "With Callback" ),
409 )
410 innerbox.Add( control, 0, wx.EXPAND)
411 self.bottommostcontrol = control = DirBrowseButton(
412 panel,
413 labelText = "Simple dir browse button",
414 style = wx.SUNKEN_BORDER|wx.CLIP_CHILDREN)
415 innerbox.Add( control, 0, wx.EXPAND)
416 ID = wx.NewId()
417 innerbox.Add( wx.Button( panel, ID,"Change Label", ), 1, wx.EXPAND)
418 self.Bind(wx.EVT_BUTTON, self.OnChangeLabel , id=ID)
419 ID = wx.NewId()
420 innerbox.Add( wx.Button( panel, ID,"Change Value", ), 1, wx.EXPAND)
421 self.Bind(wx.EVT_BUTTON, self.OnChangeValue, id=ID )
422 panel.SetAutoLayout(True)
423 panel.SetSizer( innerbox )
424 self.history={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
425
426 def historyCallBack(self):
427 keys=self.history.keys()
428 keys.sort()
429 return keys
430
431 def OnFileNameChangedHistory (self, event):
432 self.history[event.GetString ()]=1
433
434 def OnCloseMe(self, event):
435 self.Close(True)
436 def OnChangeLabel( self, event ):
437 self.bottomcontrol.SetLabel( "Label Updated" )
438 def OnChangeValue( self, event ):
439 self.bottomcontrol.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
440
441 def OnCloseWindow(self, event):
442 self.Destroy()
443
444 class DemoApp(wx.App):
445 def OnInit(self):
446 wx.InitAllImageHandlers()
447 frame = DemoFrame(None)
448 frame.Show(True)
449 self.SetTopWindow(frame)
450 return True
451
452 def test( ):
453 app = DemoApp(0)
454 app.MainLoop()
455 print 'Creating dialog'
456 test( )
457
458
459