X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6cffbf02c02c6df717dab7635c4b2031ed4d3414..c878ceeae8d69f231477ef0f207766093547ab86:/wxPython/wx/lib/masked/ipaddrctrl.py diff --git a/wxPython/wx/lib/masked/ipaddrctrl.py b/wxPython/wx/lib/masked/ipaddrctrl.py new file mode 100644 index 0000000000..9fea97faa6 --- /dev/null +++ b/wxPython/wx/lib/masked/ipaddrctrl.py @@ -0,0 +1,187 @@ +#---------------------------------------------------------------------------- +# Name: masked.ipaddrctrl.py +# Authors: Will Sadkin +# Email: wsadkin@nameconnector.com +# Created: 02/11/2003 +# Copyright: (c) 2003 by Will Sadkin, 2003 +# RCS-ID: $Id$ +# License: wxWidgets license +#---------------------------------------------------------------------------- +# NOTE: +# Masked.IpAddrCtrl is a minor modification to masked.TextCtrl, that is +# specifically tailored for entering IP addresses. It allows for +# right-insert fields and provides an accessor to obtain the entered +# address with extra whitespace removed. +# +#---------------------------------------------------------------------------- + +import wx +from wx.lib.masked import BaseMaskedTextCtrl + +# jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would +# be a good place to implement the 2.3 logger class +from wx.tools.dbg import Logger +dbg = Logger() +##dbg(enable=0) + +class IpAddrCtrlAccessorsMixin: + # Define IpAddrCtrl's list of attributes having their own + # Get/Set functions, exposing only those that make sense for + # an IP address control. + + exposed_basectrl_params = ( + 'fields', + 'retainFieldValidation', + 'formatcodes', + 'fillChar', + 'defaultValue', + 'description', + + 'useFixedWidthFont', + 'signedForegroundColour', + 'emptyBackgroundColour', + 'validBackgroundColour', + 'invalidBackgroundColour', + + 'emptyInvalid', + 'validFunc', + 'validRequired', + ) + + for param in exposed_basectrl_params: + propname = param[0].upper() + param[1:] + exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param)) + exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param)) + + if param.find('Colour') != -1: + # add non-british spellings, for backward-compatibility + propname.replace('Colour', 'Color') + + exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param)) + exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param)) + + +class IpAddrCtrl( BaseMaskedTextCtrl, IpAddrCtrlAccessorsMixin ): + """ + This class is a particular type of MaskedTextCtrl that accepts + and understands the semantics of IP addresses, reformats input + as you move from field to field, and accepts '.' as a navigation + character, so that typing an IP address can be done naturally. + """ + + + + def __init__( self, parent, id=-1, value = '', + pos = wx.DefaultPosition, + size = wx.DefaultSize, + style = wx.TE_PROCESS_TAB, + validator = wx.DefaultValidator, + name = 'IpAddrCtrl', + setupEventHandling = True, ## setup event handling by default + **kwargs): + + if not kwargs.has_key('mask'): + kwargs['mask'] = mask = "###.###.###.###" + if not kwargs.has_key('formatcodes'): + kwargs['formatcodes'] = 'F_Sr<' + if not kwargs.has_key('validRegex'): + kwargs['validRegex'] = "( \d| \d\d|(1\d\d|2[0-4]\d|25[0-5]))(\.( \d| \d\d|(1\d\d|2[0-4]\d|25[0-5]))){3}" + + + BaseMaskedTextCtrl.__init__( + self, parent, id=id, value = value, + pos=pos, size=size, + style = style, + validator = validator, + name = name, + setupEventHandling = setupEventHandling, + **kwargs) + + + # set up individual field parameters as well: + field_params = {} + field_params['validRegex'] = "( | \d| \d |\d | \d\d|\d\d |\d \d|(1\d\d|2[0-4]\d|25[0-5]))" + + # require "valid" string; this prevents entry of any value > 255, but allows + # intermediate constructions; overall control validation requires well-formatted value. + field_params['formatcodes'] = 'V' + + if field_params: + for i in self._field_indices: + self.SetFieldParameters(i, **field_params) + + # This makes '.' act like tab: + self._AddNavKey('.', handler=self.OnDot) + self._AddNavKey('>', handler=self.OnDot) # for "shift-." + + + def OnDot(self, event): +## dbg('IpAddrCtrl::OnDot', indent=1) + pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode()) + oldvalue = self.GetValue() + edit_start, edit_end, slice = self._FindFieldExtent(pos, getslice=True) + if not event.ShiftDown(): + if pos > edit_start and pos < edit_end: + # clip data in field to the right of pos, if adjusting fields + # when not at delimeter; (assumption == they hit '.') + newvalue = oldvalue[:pos] + ' ' * (edit_end - pos) + oldvalue[edit_end:] + self._SetValue(newvalue) + self._SetInsertionPoint(pos) +## dbg(indent=0) + return self._OnChangeField(event) + + + + def GetAddress(self): + value = BaseMaskedTextCtrl.GetValue(self) + return value.replace(' ','') # remove spaces from the value + + + def _OnCtrl_S(self, event): +## dbg("IpAddrCtrl::_OnCtrl_S") + if self._demo: + print "value:", self.GetAddress() + return False + + def SetValue(self, value): +## dbg('IpAddrCtrl::SetValue(%s)' % str(value), indent=1) + if type(value) not in (types.StringType, types.UnicodeType): +## dbg(indent=0) + raise ValueError('%s must be a string', str(value)) + + bValid = True # assume True + parts = value.split('.') + if len(parts) != 4: + bValid = False + else: + for i in range(4): + part = parts[i] + if not 0 <= len(part) <= 3: + bValid = False + break + elif part.strip(): # non-empty part + try: + j = string.atoi(part) + if not 0 <= j <= 255: + bValid = False + break + else: + parts[i] = '%3d' % j + except: + bValid = False + break + else: + # allow empty sections for SetValue (will result in "invalid" value, + # but this may be useful for initializing the control: + parts[i] = ' ' # convert empty field to 3-char length + + if not bValid: +## dbg(indent=0) + raise ValueError('value (%s) must be a string of form n.n.n.n where n is empty or in range 0-255' % str(value)) + else: +## dbg('parts:', parts) + value = string.join(parts, '.') + BaseMaskedTextCtrl.SetValue(self, value) +## dbg(indent=0) + +