]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/masked/textctrl.py
1 #----------------------------------------------------------------------------
2 # Name: masked.textctrl.py
3 # Authors: Jeff Childers, Will Sadkin
4 # Email: jchilders_98@yahoo.com, wsadkin@nameconnector.com
6 # Copyright: (c) 2003 by Jeff Childers, Will Sadkin, 2003
7 # Portions: (c) 2002 by Will Sadkin, 2002-2003
9 # License: wxWidgets license
10 #----------------------------------------------------------------------------
12 # This file contains the most typically used generic masked control,
13 # masked.TextCtrl. It also defines the BaseMaskedTextCtrl, which can
14 # be used to derive other "semantics-specific" classes, like masked.NumCtrl,
15 # masked.TimeCtrl, and masked.IpAddrCtrl.
17 #----------------------------------------------------------------------------
19 from wx
.lib
.masked
import *
21 # jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would
22 # be a good place to implement the 2.3 logger class
23 from wx
.tools
.dbg
import Logger
27 # ## TRICKY BIT: to avoid a ton of boiler-plate, and to
28 # ## automate the getter/setter generation for each valid
29 # ## control parameter so we never forget to add the
30 # ## functions when adding parameters, this loop
31 # ## programmatically adds them to the class:
32 # ## (This makes it easier for Designers like Boa to
33 # ## deal with masked controls.)
35 # ## To further complicate matters, this is done with an
36 # ## extra level of inheritance, so that "general" classes like
37 # ## MaskedTextCtrl can have all possible attributes,
38 # ## while derived classes, like TimeCtrl and MaskedNumCtrl
39 # ## can prevent exposure of those optional attributes of their base
40 # ## class that do not make sense for their derivation. Therefore,
42 # ## BaseMaskedTextCtrl(TextCtrl, MaskedEditMixin)
44 # ## MaskedTextCtrl(BaseMaskedTextCtrl, MaskedEditAccessorsMixin).
46 # ## This allows us to then derive:
47 # ## MaskedNumCtrl( BaseMaskedTextCtrl )
49 # ## and not have to expose all the same accessor functions for the
50 # ## derived control when they don't all make sense for it.
53 class BaseMaskedTextCtrl( wx
.TextCtrl
, MaskedEditMixin
):
55 This is the primary derivation from MaskedEditMixin. It provides
56 a general masked text control that can be configured with different
57 masks. It's actually a "base masked textCtrl", so that the
58 MaskedTextCtrl class can be derived from it, and add those
59 accessor functions to it that are appropriate to the general class,
60 whilst other classes can derive from BaseMaskedTextCtrl, and
61 only define those accessor functions that are appropriate for
65 def __init__( self
, parent
, id=-1, value
= '',
66 pos
= wx
.DefaultPosition
,
67 size
= wx
.DefaultSize
,
68 style
= wx
.TE_PROCESS_TAB
,
69 validator
=wx
.DefaultValidator
, ## placeholder provided for data-transfer logic
70 name
= 'maskedTextCtrl',
71 setupEventHandling
= True, ## setup event handling by default
74 wx
.TextCtrl
.__init
__(self
, parent
, id, value
='',
76 style
=style
, validator
=validator
,
79 self
.controlInitialized
= True
80 MaskedEditMixin
.__init
__( self
, name
, **kwargs
)
82 self
._SetInitialValue
(value
)
84 if setupEventHandling
:
85 ## Setup event handlers
86 self
.Bind(wx
.EVT_SET_FOCUS
, self
._OnFocus
) ## defeat automatic full selection
87 self
.Bind(wx
.EVT_KILL_FOCUS
, self
._OnKillFocus
) ## run internal validator
88 self
.Bind(wx
.EVT_LEFT_DCLICK
, self
._OnDoubleClick
) ## select field under cursor on dclick
89 self
.Bind(wx
.EVT_RIGHT_UP
, self
._OnContextMenu
) ## bring up an appropriate context menu
90 self
.Bind(wx
.EVT_KEY_DOWN
, self
._OnKeyDown
) ## capture control events not normally seen, eg ctrl-tab.
91 self
.Bind(wx
.EVT_CHAR
, self
._OnChar
) ## handle each keypress
92 self
.Bind(wx
.EVT_TEXT
, self
._OnTextChange
) ## color control appropriately & keep
93 ## track of previous value for undo
97 return "<BaseMaskedTextCtrl: %s>" % self
.GetValue()
100 def _GetSelection(self
):
102 Allow mixin to get the text selection of this control.
103 REQUIRED by any class derived from MaskedEditMixin.
105 return self
.GetSelection()
107 def _SetSelection(self
, sel_start
, sel_to
):
109 Allow mixin to set the text selection of this control.
110 REQUIRED by any class derived from MaskedEditMixin.
112 #### dbg("MaskedTextCtrl::_SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
113 return self
.SetSelection( sel_start
, sel_to
)
115 def SetSelection(self
, sel_start
, sel_to
):
117 This is just for debugging...
119 ## dbg("MaskedTextCtrl::SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
120 wx
.TextCtrl
.SetSelection(self
, sel_start
, sel_to
)
123 def _GetInsertionPoint(self
):
124 return self
.GetInsertionPoint()
126 def _SetInsertionPoint(self
, pos
):
127 #### dbg("MaskedTextCtrl::_SetInsertionPoint(%(pos)d)" % locals())
128 self
.SetInsertionPoint(pos
)
130 def SetInsertionPoint(self
, pos
):
132 This is just for debugging...
134 ## dbg("MaskedTextCtrl::SetInsertionPoint(%(pos)d)" % locals())
135 wx
.TextCtrl
.SetInsertionPoint(self
, pos
)
140 Allow mixin to get the raw value of the control with this function.
141 REQUIRED by any class derived from MaskedEditMixin.
143 return self
.GetValue()
145 def _SetValue(self
, value
):
147 Allow mixin to set the raw value of the control with this function.
148 REQUIRED by any class derived from MaskedEditMixin.
150 ## dbg('MaskedTextCtrl::_SetValue("%(value)s")' % locals(), indent=1)
151 # Record current selection and insertion point, for undo
152 self
._prevSelection
= self
._GetSelection
()
153 self
._prevInsertionPoint
= self
._GetInsertionPoint
()
154 wx
.TextCtrl
.SetValue(self
, value
)
157 def SetValue(self
, value
):
159 This function redefines the externally accessible .SetValue to be
160 a smart "paste" of the text in question, so as not to corrupt the
161 masked control. NOTE: this must be done in the class derived
162 from the base wx control.
164 ## dbg('MaskedTextCtrl::SetValue = "%s"' % value, indent=1)
167 wx
.TextCtrl
.SetValue(self
, value
) # revert to base control behavior
170 # empty previous contents, replacing entire value:
171 self
._SetInsertionPoint
(0)
172 self
._SetSelection
(0, self
._masklength
)
173 if self
._signOk
and self
._useParens
:
174 signpos
= value
.find('-')
176 value
= value
[:signpos
] + '(' + value
[signpos
+1:].strip() + ')'
177 elif value
.find(')') == -1 and len(value
) < self
._masklength
:
178 value
+= ' ' # add place holder for reserved space for right paren
180 if( len(value
) < self
._masklength
# value shorter than control
181 and (self
._isFloat
or self
._isInt
) # and it's a numeric control
182 and self
._ctrl
_constraints
._alignRight
): # and it's a right-aligned control
184 ## dbg('len(value)', len(value), ' < self._masklength', self._masklength)
185 # try to intelligently "pad out" the value to the right size:
186 value
= self
._template
[0:self
._masklength
- len(value
)] + value
187 if self
._isFloat
and value
.find('.') == -1:
189 ## dbg('padded value = "%s"' % value)
191 # make SetValue behave the same as if you had typed the value in:
193 value
, replace_to
= self
._Paste
(value
, raise_on_invalid
=True, just_return_value
=True)
195 self
._isNeg
= False # (clear current assumptions)
196 value
= self
._adjustFloat
(value
)
198 self
._isNeg
= False # (clear current assumptions)
199 value
= self
._adjustInt
(value
)
200 elif self
._isDate
and not self
.IsValid(value
) and self
._4digityear
:
201 value
= self
._adjustDate
(value
, fixcentury
=True)
203 # If date, year might be 2 digits vs. 4; try adjusting it:
204 if self
._isDate
and self
._4digityear
:
205 dateparts
= value
.split(' ')
206 dateparts
[0] = self
._adjustDate
(dateparts
[0], fixcentury
=True)
207 value
= string
.join(dateparts
, ' ')
208 ## dbg('adjusted value: "%s"' % value)
209 value
, replace_to
= self
._Paste
(value
, raise_on_invalid
=True, just_return_value
=True)
211 ## dbg('exception thrown', indent=0)
214 self
._SetValue
(value
) # note: to preserve similar capability, .SetValue()
215 # does not change IsModified()
216 #### dbg('queuing insertion after .SetValue', replace_to)
217 # set selection to last char replaced by paste
218 wx
.CallAfter(self
._SetInsertionPoint
, replace_to
)
219 wx
.CallAfter(self
._SetSelection
, replace_to
, replace_to
)
224 """ Blanks the current control value by replacing it with the default value."""
225 ## dbg("MaskedTextCtrl::Clear - value reset to default value (template)")
229 wx
.TextCtrl
.Clear(self
) # else revert to base control behavior
234 Allow mixin to refresh the base control with this function.
235 REQUIRED by any class derived from MaskedEditMixin.
237 ## dbg('MaskedTextCtrl::_Refresh', indent=1)
238 wx
.TextCtrl
.Refresh(self
)
244 This function redefines the externally accessible .Refresh() to
245 validate the contents of the masked control as it refreshes.
246 NOTE: this must be done in the class derived from the base wx control.
248 ## dbg('MaskedTextCtrl::Refresh', indent=1)
254 def _IsEditable(self
):
256 Allow mixin to determine if the base control is editable with this function.
257 REQUIRED by any class derived from MaskedEditMixin.
259 return wx
.TextCtrl
.IsEditable(self
)
264 This function redefines the externally accessible .Cut to be
265 a smart "erase" of the text in question, so as not to corrupt the
266 masked control. NOTE: this must be done in the class derived
267 from the base wx control.
270 self
._Cut
() # call the mixin's Cut method
272 wx
.TextCtrl
.Cut(self
) # else revert to base control behavior
277 This function redefines the externally accessible .Paste to be
278 a smart "paste" of the text in question, so as not to corrupt the
279 masked control. NOTE: this must be done in the class derived
280 from the base wx control.
283 self
._Paste
() # call the mixin's Paste method
285 wx
.TextCtrl
.Paste(self
, value
) # else revert to base control behavior
290 This function defines the undo operation for the control. (The default
296 wx
.TextCtrl
.Undo(self
) # else revert to base control behavior
299 def IsModified(self
):
301 This function overrides the raw wxTextCtrl method, because the
302 masked edit mixin uses SetValue to change the value, which doesn't
303 modify the state of this attribute. So, we keep track on each
304 keystroke to see if the value changes, and if so, it's been
307 return wx
.TextCtrl
.IsModified(self
) or self
.modified
310 def _CalcSize(self
, size
=None):
312 Calculate automatic size if allowed; use base mixin function.
314 return self
._calcSize
(size
)
317 class TextCtrl( BaseMaskedTextCtrl
, MaskedEditAccessorsMixin
):
319 This extra level of inheritance allows us to add the generic set of
320 masked edit parameters only to this class while allowing other
321 classes to derive from the "base" masked text control, and provide
322 a smaller set of valid accessor functions.