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