--- /dev/null
+#----------------------------------------------------------------------------
+# 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)
+
+