]>
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
= 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
= 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', self._masklength)
217 wx
.CallAfter(self
._SetInsertionPoint
, self
._masklength
)
218 wx
.CallAfter(self
._SetSelection
, self
._masklength
, self
._masklength
)
223 """ Blanks the current control value by replacing it with the default value."""
224 ## dbg("MaskedTextCtrl::Clear - value reset to default value (template)")
228 wx
.TextCtrl
.Clear(self
) # else revert to base control behavior
233 Allow mixin to refresh the base control with this function.
234 REQUIRED by any class derived from MaskedEditMixin.
236 ## dbg('MaskedTextCtrl::_Refresh', indent=1)
237 wx
.TextCtrl
.Refresh(self
)
243 This function redefines the externally accessible .Refresh() to
244 validate the contents of the masked control as it refreshes.
245 NOTE: this must be done in the class derived from the base wx control.
247 ## dbg('MaskedTextCtrl::Refresh', indent=1)
253 def _IsEditable(self
):
255 Allow mixin to determine if the base control is editable with this function.
256 REQUIRED by any class derived from MaskedEditMixin.
258 return wx
.TextCtrl
.IsEditable(self
)
263 This function redefines the externally accessible .Cut to be
264 a smart "erase" of the text in question, so as not to corrupt the
265 masked control. NOTE: this must be done in the class derived
266 from the base wx control.
269 self
._Cut
() # call the mixin's Cut method
271 wx
.TextCtrl
.Cut(self
) # else revert to base control behavior
276 This function redefines the externally accessible .Paste to be
277 a smart "paste" of the text in question, so as not to corrupt the
278 masked control. NOTE: this must be done in the class derived
279 from the base wx control.
282 self
._Paste
() # call the mixin's Paste method
284 wx
.TextCtrl
.Paste(self
, value
) # else revert to base control behavior
289 This function defines the undo operation for the control. (The default
295 wx
.TextCtrl
.Undo(self
) # else revert to base control behavior
298 def IsModified(self
):
300 This function overrides the raw wxTextCtrl method, because the
301 masked edit mixin uses SetValue to change the value, which doesn't
302 modify the state of this attribute. So, we keep track on each
303 keystroke to see if the value changes, and if so, it's been
306 return wx
.TextCtrl
.IsModified(self
) or self
.modified
309 def _CalcSize(self
, size
=None):
311 Calculate automatic size if allowed; use base mixin function.
313 return self
._calcSize
(size
)
316 class TextCtrl( BaseMaskedTextCtrl
, MaskedEditAccessorsMixin
):
318 This extra level of inheritance allows us to add the generic set of
319 masked edit parameters only to this class while allowing other
320 classes to derive from the "base" masked text control, and provide
321 a smaller set of valid accessor functions.