]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/lib/masked/textctrl.py
Publisher is now able to parse a dotted notation string
[wxWidgets.git] / wxPython / wx / lib / masked / textctrl.py
CommitLineData
c878ceea
RD
1#----------------------------------------------------------------------------
2# Name: masked.textctrl.py
3# Authors: Jeff Childers, Will Sadkin
4# Email: jchilders_98@yahoo.com, wsadkin@nameconnector.com
5# Created: 02/11/2003
6# Copyright: (c) 2003 by Jeff Childers, Will Sadkin, 2003
7# Portions: (c) 2002 by Will Sadkin, 2002-2003
8# RCS-ID: $Id$
9# License: wxWidgets license
10#----------------------------------------------------------------------------
11#
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.
16#
17#----------------------------------------------------------------------------
f54a36bb
RD
18"""
19Provides a generic, fully configurable masked edit text control, as well as
20a base class from which you can derive masked controls tailored to a specific
21function. See maskededit module overview for how to configure the control.
22"""
23
c878ceea
RD
24import wx
25from wx.lib.masked import *
26
27# jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would
28# be a good place to implement the 2.3 logger class
29from wx.tools.dbg import Logger
f54a36bb 30##dbg = Logger()
339983ff 31##dbg(enable=1)
c878ceea 32
c878ceea
RD
33
34class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
35 """
36 This is the primary derivation from MaskedEditMixin. It provides
37 a general masked text control that can be configured with different
f54a36bb
RD
38 masks.
39
40 However, this is done with an extra level of inheritance, so that
41 "general" classes like masked.TextCtrl can have all possible attributes,
42 while derived classes, like masked.TimeCtrl and masked.NumCtrl
43 can prevent exposure of those optional attributes of their base
44 class that do not make sense for their derivation. Therefore,
45 we define::
46
47 BaseMaskedTextCtrl(TextCtrl, MaskedEditMixin)
48
49 and::
50
51 masked.TextCtrl(BaseMaskedTextCtrl, MaskedEditAccessorsMixin).
52
53 This allows us to then derive::
54
55 masked.NumCtrl( BaseMaskedTextCtrl )
56
57 and not have to expose all the same accessor functions for the
58 derived control when they don't all make sense for it.
59
60 In practice, BaseMaskedTextCtrl should never be instantiated directly,
61 but should only be used in derived classes.
c878ceea
RD
62 """
63
64 def __init__( self, parent, id=-1, value = '',
65 pos = wx.DefaultPosition,
66 size = wx.DefaultSize,
67 style = wx.TE_PROCESS_TAB,
68 validator=wx.DefaultValidator, ## placeholder provided for data-transfer logic
69 name = 'maskedTextCtrl',
70 setupEventHandling = True, ## setup event handling by default
71 **kwargs):
72
73 wx.TextCtrl.__init__(self, parent, id, value='',
74 pos=pos, size = size,
75 style=style, validator=validator,
76 name=name)
77
339983ff
RD
78 self._PostInit(setupEventHandling = setupEventHandling,
79 name=name, value=value,**kwargs )
80
81
82 def _PostInit(self,setupEventHandling=True,
83 name='maskedTextCtrl' , value='', **kwargs):
84
c878ceea
RD
85 self.controlInitialized = True
86 MaskedEditMixin.__init__( self, name, **kwargs )
87
88 self._SetInitialValue(value)
89
90 if setupEventHandling:
91 ## Setup event handlers
92 self.Bind(wx.EVT_SET_FOCUS, self._OnFocus ) ## defeat automatic full selection
93 self.Bind(wx.EVT_KILL_FOCUS, self._OnKillFocus ) ## run internal validator
94 self.Bind(wx.EVT_LEFT_DCLICK, self._OnDoubleClick) ## select field under cursor on dclick
95 self.Bind(wx.EVT_RIGHT_UP, self._OnContextMenu ) ## bring up an appropriate context menu
96 self.Bind(wx.EVT_KEY_DOWN, self._OnKeyDown ) ## capture control events not normally seen, eg ctrl-tab.
97 self.Bind(wx.EVT_CHAR, self._OnChar ) ## handle each keypress
98 self.Bind(wx.EVT_TEXT, self._OnTextChange ) ## color control appropriately & keep
99 ## track of previous value for undo
100
101
102 def __repr__(self):
103 return "<BaseMaskedTextCtrl: %s>" % self.GetValue()
104
105
106 def _GetSelection(self):
107 """
108 Allow mixin to get the text selection of this control.
109 REQUIRED by any class derived from MaskedEditMixin.
110 """
111 return self.GetSelection()
112
113 def _SetSelection(self, sel_start, sel_to):
114 """
115 Allow mixin to set the text selection of this control.
116 REQUIRED by any class derived from MaskedEditMixin.
117 """
118#### dbg("MaskedTextCtrl::_SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
119 return self.SetSelection( sel_start, sel_to )
120
f54a36bb
RD
121## def SetSelection(self, sel_start, sel_to):
122## """
123## This is just for debugging...
124## """
c878ceea 125## dbg("MaskedTextCtrl::SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
f54a36bb 126## wx.TextCtrl.SetSelection(self, sel_start, sel_to)
c878ceea
RD
127
128
129 def _GetInsertionPoint(self):
130 return self.GetInsertionPoint()
131
132 def _SetInsertionPoint(self, pos):
133#### dbg("MaskedTextCtrl::_SetInsertionPoint(%(pos)d)" % locals())
134 self.SetInsertionPoint(pos)
135
f54a36bb
RD
136## def SetInsertionPoint(self, pos):
137## """
138## This is just for debugging...
139## """
c878ceea 140## dbg("MaskedTextCtrl::SetInsertionPoint(%(pos)d)" % locals())
f54a36bb 141## wx.TextCtrl.SetInsertionPoint(self, pos)
c878ceea
RD
142
143
144 def _GetValue(self):
145 """
146 Allow mixin to get the raw value of the control with this function.
147 REQUIRED by any class derived from MaskedEditMixin.
148 """
149 return self.GetValue()
150
f54a36bb 151
c878ceea
RD
152 def _SetValue(self, value):
153 """
154 Allow mixin to set the raw value of the control with this function.
155 REQUIRED by any class derived from MaskedEditMixin.
156 """
157## dbg('MaskedTextCtrl::_SetValue("%(value)s")' % locals(), indent=1)
158 # Record current selection and insertion point, for undo
159 self._prevSelection = self._GetSelection()
160 self._prevInsertionPoint = self._GetInsertionPoint()
161 wx.TextCtrl.SetValue(self, value)
162## dbg(indent=0)
163
164 def SetValue(self, value):
165 """
f54a36bb 166 This function redefines the externally accessible .SetValue() to be
c878ceea
RD
167 a smart "paste" of the text in question, so as not to corrupt the
168 masked control. NOTE: this must be done in the class derived
169 from the base wx control.
170 """
171## dbg('MaskedTextCtrl::SetValue = "%s"' % value, indent=1)
172
173 if not self._mask:
174 wx.TextCtrl.SetValue(self, value) # revert to base control behavior
175 return
176
177 # empty previous contents, replacing entire value:
178 self._SetInsertionPoint(0)
179 self._SetSelection(0, self._masklength)
180 if self._signOk and self._useParens:
181 signpos = value.find('-')
182 if signpos != -1:
183 value = value[:signpos] + '(' + value[signpos+1:].strip() + ')'
184 elif value.find(')') == -1 and len(value) < self._masklength:
185 value += ' ' # add place holder for reserved space for right paren
186
187 if( len(value) < self._masklength # value shorter than control
188 and (self._isFloat or self._isInt) # and it's a numeric control
189 and self._ctrl_constraints._alignRight ): # and it's a right-aligned control
190
191## dbg('len(value)', len(value), ' < self._masklength', self._masklength)
192 # try to intelligently "pad out" the value to the right size:
193 value = self._template[0:self._masklength - len(value)] + value
194 if self._isFloat and value.find('.') == -1:
195 value = value[1:]
196## dbg('padded value = "%s"' % value)
197
198 # make SetValue behave the same as if you had typed the value in:
199 try:
5f280eaa 200 value, replace_to = self._Paste(value, raise_on_invalid=True, just_return_value=True)
c878ceea
RD
201 if self._isFloat:
202 self._isNeg = False # (clear current assumptions)
203 value = self._adjustFloat(value)
204 elif self._isInt:
205 self._isNeg = False # (clear current assumptions)
206 value = self._adjustInt(value)
207 elif self._isDate and not self.IsValid(value) and self._4digityear:
208 value = self._adjustDate(value, fixcentury=True)
209 except ValueError:
210 # If date, year might be 2 digits vs. 4; try adjusting it:
211 if self._isDate and self._4digityear:
212 dateparts = value.split(' ')
213 dateparts[0] = self._adjustDate(dateparts[0], fixcentury=True)
214 value = string.join(dateparts, ' ')
215## dbg('adjusted value: "%s"' % value)
5f280eaa 216 value, replace_to = self._Paste(value, raise_on_invalid=True, just_return_value=True)
c878ceea
RD
217 else:
218## dbg('exception thrown', indent=0)
219 raise
220
221 self._SetValue(value) # note: to preserve similar capability, .SetValue()
222 # does not change IsModified()
5f280eaa
RD
223#### dbg('queuing insertion after .SetValue', replace_to)
224 # set selection to last char replaced by paste
225 wx.CallAfter(self._SetInsertionPoint, replace_to)
226 wx.CallAfter(self._SetSelection, replace_to, replace_to)
c878ceea
RD
227## dbg(indent=0)
228
f54a36bb 229
339983ff
RD
230 def SetFont(self, *args, **kwargs):
231 """ Set the font, then recalculate control size, if appropriate. """
232 wx.TextCtrl.SetFont(self, *args, **kwargs)
233 if self._autofit:
234## dbg('calculated size:', self._CalcSize())
235 self.SetClientSize(self._CalcSize())
236 width = self.GetSize().width
237 height = self.GetBestSize().height
238## dbg('setting client size to:', (width, height))
5193b348 239 self.SetBestFittingSize((width, height))
339983ff 240
c878ceea
RD
241
242 def Clear(self):
243 """ Blanks the current control value by replacing it with the default value."""
244## dbg("MaskedTextCtrl::Clear - value reset to default value (template)")
245 if self._mask:
246 self.ClearValue()
247 else:
248 wx.TextCtrl.Clear(self) # else revert to base control behavior
249
250
251 def _Refresh(self):
252 """
253 Allow mixin to refresh the base control with this function.
254 REQUIRED by any class derived from MaskedEditMixin.
255 """
256## dbg('MaskedTextCtrl::_Refresh', indent=1)
257 wx.TextCtrl.Refresh(self)
258## dbg(indent=0)
259
260
261 def Refresh(self):
262 """
263 This function redefines the externally accessible .Refresh() to
264 validate the contents of the masked control as it refreshes.
265 NOTE: this must be done in the class derived from the base wx control.
266 """
267## dbg('MaskedTextCtrl::Refresh', indent=1)
268 self._CheckValid()
269 self._Refresh()
270## dbg(indent=0)
271
272
273 def _IsEditable(self):
274 """
275 Allow mixin to determine if the base control is editable with this function.
276 REQUIRED by any class derived from MaskedEditMixin.
277 """
278 return wx.TextCtrl.IsEditable(self)
279
280
281 def Cut(self):
282 """
283 This function redefines the externally accessible .Cut to be
284 a smart "erase" of the text in question, so as not to corrupt the
285 masked control. NOTE: this must be done in the class derived
286 from the base wx control.
287 """
288 if self._mask:
289 self._Cut() # call the mixin's Cut method
290 else:
291 wx.TextCtrl.Cut(self) # else revert to base control behavior
292
293
294 def Paste(self):
295 """
296 This function redefines the externally accessible .Paste to be
297 a smart "paste" of the text in question, so as not to corrupt the
298 masked control. NOTE: this must be done in the class derived
299 from the base wx control.
300 """
301 if self._mask:
302 self._Paste() # call the mixin's Paste method
303 else:
304 wx.TextCtrl.Paste(self, value) # else revert to base control behavior
305
306
307 def Undo(self):
308 """
309 This function defines the undo operation for the control. (The default
310 undo is 1-deep.)
311 """
312 if self._mask:
313 self._Undo()
314 else:
315 wx.TextCtrl.Undo(self) # else revert to base control behavior
316
317
318 def IsModified(self):
319 """
f54a36bb 320 This function overrides the raw wx.TextCtrl method, because the
c878ceea 321 masked edit mixin uses SetValue to change the value, which doesn't
f54a36bb
RD
322 modify the state of this attribute. So, the derived control keeps track
323 on each keystroke to see if the value changes, and if so, it's been
c878ceea
RD
324 modified.
325 """
326 return wx.TextCtrl.IsModified(self) or self.modified
327
328
329 def _CalcSize(self, size=None):
330 """
331 Calculate automatic size if allowed; use base mixin function.
332 """
333 return self._calcSize(size)
334
335
336class TextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ):
337 """
f54a36bb
RD
338 The "user-visible" masked text control; it is identical to the
339 BaseMaskedTextCtrl class it's derived from.
340 (This extra level of inheritance allows us to add the generic
341 set of masked edit parameters only to this class while allowing
342 other classes to derive from the "base" masked text control,
343 and provide a smaller set of valid accessor functions.)
344 See BaseMaskedTextCtrl for available methods.
c878ceea
RD
345 """
346 pass
347
348
339983ff
RD
349class PreMaskedTextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ):
350 """
f54a36bb 351 This class exists to support the use of XRC subclassing.
339983ff
RD
352 """
353 # This should really be wx.EVT_WINDOW_CREATE but it is not
354 # currently delivered for native controls on all platforms, so
355 # we'll use EVT_SIZE instead. It should happen shortly after the
356 # control is created as the control is set to its "best" size.
357 _firstEventType = wx.EVT_SIZE
358
359 def __init__(self):
360 pre = wx.PreTextCtrl()
361 self.PostCreate(pre)
362 self.Bind(self._firstEventType, self.OnCreate)
363
364
365 def OnCreate(self, evt):
366 self.Unbind(self._firstEventType)
367 self._PostInit()
368
f54a36bb 369__i=0
339983ff
RD
370## CHANGELOG:
371## ====================
f54a36bb
RD
372## Version 1.2
373## - Converted docstrings to reST format, added doc for ePyDoc.
374## removed debugging override functions.
375##
339983ff
RD
376## Version 1.1
377## 1. Added .SetFont() method that properly resizes control
378## 2. Modified control to support construction via XRC mechanism.