]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/masked/ipaddrctrl.py
Added new MaskedEditControl code from Will Sadkin. The modules are
[wxWidgets.git] / 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 (file)
index 0000000..9fea97f
--- /dev/null
@@ -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)
+
+