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