]>
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.