]>
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 Provides a generic, fully configurable masked edit text control, as well as 
  20 a base class from which you can derive masked controls tailored to a specific 
  21 function.  See maskededit module overview for how to configure the control. 
  25 from wx
.lib
.masked 
import * 
  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 
  29 from wx
.tools
.dbg 
import Logger
 
  34 class BaseMaskedTextCtrl( wx
.TextCtrl
, MaskedEditMixin 
): 
  36     This is the primary derivation from MaskedEditMixin.  It provides 
  37     a general masked text control that can be configured with different 
  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, 
  47         BaseMaskedTextCtrl(TextCtrl, MaskedEditMixin) 
  51         masked.TextCtrl(BaseMaskedTextCtrl, MaskedEditAccessorsMixin). 
  53     This allows us to then derive:: 
  55         masked.NumCtrl( BaseMaskedTextCtrl ) 
  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. 
  60     In practice, BaseMaskedTextCtrl should never be instantiated directly, 
  61     but should only be used in derived classes. 
  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 
  73         wx
.TextCtrl
.__init
__(self
, parent
, id, value
='', 
  75                             style
=style
, validator
=validator
, 
  78         self
._PostInit
(setupEventHandling 
= setupEventHandling
, 
  79                       name
=name
, value
=value
,**kwargs 
) 
  82     def _PostInit(self
,setupEventHandling
=True, 
  83                  name
='maskedTextCtrl' , value
='', **kwargs
): 
  85         self
.controlInitialized 
= True 
  86         MaskedEditMixin
.__init
__( self
, name
, **kwargs 
) 
  88         self
._SetInitialValue
(value
) 
  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 
 103         return "<BaseMaskedTextCtrl: %s>" % self
.GetValue() 
 106     def _GetSelection(self
): 
 108         Allow mixin to get the text selection of this control. 
 109         REQUIRED by any class derived from MaskedEditMixin. 
 111         return self
.GetSelection() 
 113     def _SetSelection(self
, sel_start
, sel_to
): 
 115         Allow mixin to set the text selection of this control. 
 116         REQUIRED by any class derived from MaskedEditMixin. 
 118 ####        dbg("MaskedTextCtrl::_SetSelection(%(sel_start)d, %(sel_to)d)" % locals()) 
 119         return self
.SetSelection( sel_start
, sel_to 
) 
 121 ##    def SetSelection(self, sel_start, sel_to): 
 123 ##        This is just for debugging... 
 125 ##        dbg("MaskedTextCtrl::SetSelection(%(sel_start)d, %(sel_to)d)" % locals()) 
 126 ##        wx.TextCtrl.SetSelection(self, sel_start, sel_to) 
 129     def _GetInsertionPoint(self
): 
 130         return self
.GetInsertionPoint() 
 132     def _SetInsertionPoint(self
, pos
): 
 133 ####        dbg("MaskedTextCtrl::_SetInsertionPoint(%(pos)d)" % locals()) 
 134         self
.SetInsertionPoint(pos
) 
 136 ##    def SetInsertionPoint(self, pos): 
 138 ##        This is just for debugging... 
 140 ##        dbg("MaskedTextCtrl::SetInsertionPoint(%(pos)d)" % locals()) 
 141 ##        wx.TextCtrl.SetInsertionPoint(self, pos) 
 144     def IsEmpty(*args
, **kw
): 
 145         return MaskedEditMixin
.IsEmpty(*args
, **kw
) 
 149         Allow mixin to get the raw value of the control with this function. 
 150         REQUIRED by any class derived from MaskedEditMixin. 
 152         return self
.GetValue() 
 155     def _SetValue(self
, value
): 
 157         Allow mixin to set the raw value of the control with this function. 
 158         REQUIRED by any class derived from MaskedEditMixin. 
 160 ##        dbg('MaskedTextCtrl::_SetValue("%(value)s")' % locals(), indent=1) 
 161         # Record current selection and insertion point, for undo 
 162         self
._prevSelection 
= self
._GetSelection
() 
 163         self
._prevInsertionPoint 
= self
._GetInsertionPoint
() 
 164         wx
.TextCtrl
.SetValue(self
, value
) 
 167     def SetValue(self
, value
): 
 169         This function redefines the externally accessible .SetValue() to be 
 170         a smart "paste" of the text in question, so as not to corrupt the 
 171         masked control.  NOTE: this must be done in the class derived 
 172         from the base wx control. 
 174 ##        dbg('MaskedTextCtrl::SetValue = "%s"' % value, indent=1) 
 177             wx
.TextCtrl
.SetValue(self
, value
)    # revert to base control behavior 
 180         # empty previous contents, replacing entire value: 
 181         self
._SetInsertionPoint
(0) 
 182         self
._SetSelection
(0, self
._masklength
) 
 183         if self
._signOk 
and self
._useParens
: 
 184             signpos 
= value
.find('-') 
 186                 value 
= value
[:signpos
] + '(' + value
[signpos
+1:].strip() + ')' 
 187             elif value
.find(')') == -1 and len(value
) < self
._masklength
: 
 188                 value 
+= ' '    # add place holder for reserved space for right paren 
 190         if( len(value
) < self
._masklength                
# value shorter than control 
 191             and (self
._isFloat 
or self
._isInt
)            # and it's a numeric control 
 192             and self
._ctrl
_constraints
._alignRight 
):   # and it's a right-aligned control 
 194 ##            dbg('len(value)', len(value), ' < self._masklength', self._masklength) 
 195             # try to intelligently "pad out" the value to the right size: 
 196             value 
= self
._template
[0:self
._masklength 
- len(value
)] + value
 
 197             if self
._isFloat 
and value
.find('.') == -1: 
 199 ##            dbg('padded value = "%s"' % value) 
 201         # make SetValue behave the same as if you had typed the value in: 
 203             value
, replace_to 
= self
._Paste
(value
, raise_on_invalid
=True, just_return_value
=True) 
 205                 self
._isNeg 
= False     # (clear current assumptions) 
 206                 value 
= self
._adjustFloat
(value
) 
 208                 self
._isNeg 
= False     # (clear current assumptions) 
 209                 value 
= self
._adjustInt
(value
) 
 210             elif self
._isDate 
and not self
.IsValid(value
) and self
._4digityear
: 
 211                 value 
= self
._adjustDate
(value
, fixcentury
=True) 
 213             # If date, year might be 2 digits vs. 4; try adjusting it: 
 214             if self
._isDate 
and self
._4digityear
: 
 215                 dateparts 
= value
.split(' ') 
 216                 dateparts
[0] = self
._adjustDate
(dateparts
[0], fixcentury
=True) 
 217                 value 
= string
.join(dateparts
, ' ') 
 218 ##                dbg('adjusted value: "%s"' % value) 
 219                 value
, replace_to 
= self
._Paste
(value
, raise_on_invalid
=True, just_return_value
=True) 
 221 ##                dbg('exception thrown', indent=0) 
 224         self
._SetValue
(value
)   # note: to preserve similar capability, .SetValue() 
 225                                 # does not change IsModified() 
 226 ####        dbg('queuing insertion after .SetValue', replace_to) 
 227         # set selection to last char replaced by paste 
 228         wx
.CallAfter(self
._SetInsertionPoint
, replace_to
) 
 229         wx
.CallAfter(self
._SetSelection
, replace_to
, replace_to
) 
 233     def SetFont(self
, *args
, **kwargs
): 
 234         """ Set the font, then recalculate control size, if appropriate. """ 
 235         wx
.TextCtrl
.SetFont(self
, *args
, **kwargs
) 
 237 ##            dbg('calculated size:', self._CalcSize())             
 238             self
.SetClientSize(self
._CalcSize
()) 
 239             width 
= self
.GetSize().width
 
 240             height 
= self
.GetBestSize().height
 
 241 ##            dbg('setting client size to:', (width, height)) 
 242             self
.SetInitialSize((width
, height
)) 
 246         """ Blanks the current control value by replacing it with the default value.""" 
 247 ##        dbg("MaskedTextCtrl::Clear - value reset to default value (template)") 
 251             wx
.TextCtrl
.Clear(self
)    # else revert to base control behavior 
 256         Allow mixin to refresh the base control with this function. 
 257         REQUIRED by any class derived from MaskedEditMixin. 
 259 ##        dbg('MaskedTextCtrl::_Refresh', indent=1) 
 260         wx
.TextCtrl
.Refresh(self
) 
 266         This function redefines the externally accessible .Refresh() to 
 267         validate the contents of the masked control as it refreshes. 
 268         NOTE: this must be done in the class derived from the base wx control. 
 270 ##        dbg('MaskedTextCtrl::Refresh', indent=1) 
 276     def _IsEditable(self
): 
 278         Allow mixin to determine if the base control is editable with this function. 
 279         REQUIRED by any class derived from MaskedEditMixin. 
 281         return wx
.TextCtrl
.IsEditable(self
) 
 286         This function redefines the externally accessible .Cut to be 
 287         a smart "erase" of the text in question, so as not to corrupt the 
 288         masked control.  NOTE: this must be done in the class derived 
 289         from the base wx control. 
 292             self
._Cut
()             # call the mixin's Cut method 
 294             wx
.TextCtrl
.Cut(self
)    # else revert to base control behavior 
 299         This function redefines the externally accessible .Paste to be 
 300         a smart "paste" of the text in question, so as not to corrupt the 
 301         masked control.  NOTE: this must be done in the class derived 
 302         from the base wx control. 
 305             self
._Paste
()                   # call the mixin's Paste method 
 307             wx
.TextCtrl
.Paste(self
, value
)   # else revert to base control behavior 
 312         This function defines the undo operation for the control. (The default 
 318             wx
.TextCtrl
.Undo(self
)   # else revert to base control behavior 
 321     def IsModified(self
): 
 323         This function overrides the raw wx.TextCtrl method, because the 
 324         masked edit mixin uses SetValue to change the value, which doesn't 
 325         modify the state of this attribute.  So, the derived control keeps track 
 326         on each keystroke to see if the value changes, and if so, it's been 
 329         return wx
.TextCtrl
.IsModified(self
) or self
.modified
 
 332     def _CalcSize(self
, size
=None): 
 334         Calculate automatic size if allowed; use base mixin function. 
 336         return self
._calcSize
(size
) 
 339 class TextCtrl( BaseMaskedTextCtrl
, MaskedEditAccessorsMixin 
): 
 341     The "user-visible" masked text control; it is identical to the 
 342     BaseMaskedTextCtrl class it's derived from. 
 343     (This extra level of inheritance allows us to add the generic 
 344     set of masked edit parameters only to this class while allowing 
 345     other classes to derive from the "base" masked text control, 
 346     and provide a smaller set of valid accessor functions.) 
 347     See BaseMaskedTextCtrl for available methods. 
 352 class PreMaskedTextCtrl( BaseMaskedTextCtrl
, MaskedEditAccessorsMixin 
): 
 354     This class exists to support the use of XRC subclassing. 
 356     # This should really be wx.EVT_WINDOW_CREATE but it is not 
 357     # currently delivered for native controls on all platforms, so 
 358     # we'll use EVT_SIZE instead.  It should happen shortly after the 
 359     # control is created as the control is set to its "best" size. 
 360     _firstEventType 
= wx
.EVT_SIZE
 
 363         pre 
= wx
.PreTextCtrl() 
 365         self
.Bind(self
._firstEventType
, self
.OnCreate
) 
 368     def OnCreate(self
, evt
): 
 369         self
.Unbind(self
._firstEventType
) 
 374 ## ==================== 
 376 ##  - Converted docstrings to reST format, added doc for ePyDoc. 
 377 ##    removed debugging override functions. 
 380 ##  1. Added .SetFont() method that properly resizes control 
 381 ##  2. Modified control to support construction via XRC mechanism.