]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/lib/masked/ipaddrctrl.py
wxCheckListBox doesn't require wxUSE_OWNER_DRAWN when using WXUNIVERSAL
[wxWidgets.git] / wxPython / wx / lib / masked / ipaddrctrl.py
CommitLineData
c878ceea
RD
1#----------------------------------------------------------------------------
2# Name: masked.ipaddrctrl.py
3# Authors: Will Sadkin
4# Email: wsadkin@nameconnector.com
5# Created: 02/11/2003
6# Copyright: (c) 2003 by Will Sadkin, 2003
7# RCS-ID: $Id$
8# License: wxWidgets license
9#----------------------------------------------------------------------------
10# NOTE:
11# Masked.IpAddrCtrl is a minor modification to masked.TextCtrl, that is
12# specifically tailored for entering IP addresses. It allows for
13# right-insert fields and provides an accessor to obtain the entered
14# address with extra whitespace removed.
15#
16#----------------------------------------------------------------------------
f54a36bb
RD
17"""
18Provides a smart text input control that understands the structure and
19limits of IP Addresses, and allows automatic field navigation as the
20user hits '.' when typing.
21"""
c878ceea 22
f54a36bb 23import wx, types, string
c878ceea
RD
24from wx.lib.masked import BaseMaskedTextCtrl
25
26# jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would
27# be a good place to implement the 2.3 logger class
28from wx.tools.dbg import Logger
f54a36bb 29##dbg = Logger()
c878ceea
RD
30##dbg(enable=0)
31
32class IpAddrCtrlAccessorsMixin:
f54a36bb
RD
33 """
34 Defines IpAddrCtrl's list of attributes having their own
35 Get/Set functions, exposing only those that make sense for
36 an IP address control.
37 """
c878ceea
RD
38
39 exposed_basectrl_params = (
40 'fields',
41 'retainFieldValidation',
42 'formatcodes',
43 'fillChar',
44 'defaultValue',
45 'description',
46
47 'useFixedWidthFont',
48 'signedForegroundColour',
49 'emptyBackgroundColour',
50 'validBackgroundColour',
51 'invalidBackgroundColour',
52
53 'emptyInvalid',
54 'validFunc',
55 'validRequired',
56 )
57
58 for param in exposed_basectrl_params:
59 propname = param[0].upper() + param[1:]
60 exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param))
61 exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param))
62
63 if param.find('Colour') != -1:
64 # add non-british spellings, for backward-compatibility
65 propname.replace('Colour', 'Color')
66
67 exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param))
68 exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param))
69
70
71class IpAddrCtrl( BaseMaskedTextCtrl, IpAddrCtrlAccessorsMixin ):
72 """
73 This class is a particular type of MaskedTextCtrl that accepts
74 and understands the semantics of IP addresses, reformats input
75 as you move from field to field, and accepts '.' as a navigation
76 character, so that typing an IP address can be done naturally.
77 """
78
79
80
81 def __init__( self, parent, id=-1, value = '',
82 pos = wx.DefaultPosition,
83 size = wx.DefaultSize,
84 style = wx.TE_PROCESS_TAB,
85 validator = wx.DefaultValidator,
86 name = 'IpAddrCtrl',
87 setupEventHandling = True, ## setup event handling by default
88 **kwargs):
89
90 if not kwargs.has_key('mask'):
91 kwargs['mask'] = mask = "###.###.###.###"
92 if not kwargs.has_key('formatcodes'):
5f280eaa 93 kwargs['formatcodes'] = 'F_Sr<>'
c878ceea
RD
94 if not kwargs.has_key('validRegex'):
95 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}"
96
97
98 BaseMaskedTextCtrl.__init__(
99 self, parent, id=id, value = value,
100 pos=pos, size=size,
101 style = style,
102 validator = validator,
103 name = name,
104 setupEventHandling = setupEventHandling,
105 **kwargs)
106
107
108 # set up individual field parameters as well:
109 field_params = {}
110 field_params['validRegex'] = "( | \d| \d |\d | \d\d|\d\d |\d \d|(1\d\d|2[0-4]\d|25[0-5]))"
111
112 # require "valid" string; this prevents entry of any value > 255, but allows
113 # intermediate constructions; overall control validation requires well-formatted value.
114 field_params['formatcodes'] = 'V'
115
116 if field_params:
117 for i in self._field_indices:
118 self.SetFieldParameters(i, **field_params)
119
120 # This makes '.' act like tab:
121 self._AddNavKey('.', handler=self.OnDot)
122 self._AddNavKey('>', handler=self.OnDot) # for "shift-."
123
124
125 def OnDot(self, event):
f54a36bb
RD
126 """
127 Defines what action to take when the '.' character is typed in the
128 control. By default, the current field is right-justified, and the
129 cursor is placed in the next field.
130 """
c878ceea
RD
131## dbg('IpAddrCtrl::OnDot', indent=1)
132 pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode())
133 oldvalue = self.GetValue()
134 edit_start, edit_end, slice = self._FindFieldExtent(pos, getslice=True)
135 if not event.ShiftDown():
136 if pos > edit_start and pos < edit_end:
137 # clip data in field to the right of pos, if adjusting fields
138 # when not at delimeter; (assumption == they hit '.')
139 newvalue = oldvalue[:pos] + ' ' * (edit_end - pos) + oldvalue[edit_end:]
140 self._SetValue(newvalue)
141 self._SetInsertionPoint(pos)
142## dbg(indent=0)
143 return self._OnChangeField(event)
144
145
146
147 def GetAddress(self):
f54a36bb
RD
148 """
149 Returns the control value, with any spaces removed.
150 """
c878ceea
RD
151 value = BaseMaskedTextCtrl.GetValue(self)
152 return value.replace(' ','') # remove spaces from the value
153
154
155 def _OnCtrl_S(self, event):
156## dbg("IpAddrCtrl::_OnCtrl_S")
157 if self._demo:
158 print "value:", self.GetAddress()
159 return False
160
161 def SetValue(self, value):
f54a36bb
RD
162 """
163 Takes a string value, validates it for a valid IP address,
164 splits it into an array of 4 fields, justifies it
165 appropriately, and inserts it into the control.
166 Invalid values will raise a ValueError exception.
167 """
c878ceea
RD
168## dbg('IpAddrCtrl::SetValue(%s)' % str(value), indent=1)
169 if type(value) not in (types.StringType, types.UnicodeType):
170## dbg(indent=0)
171 raise ValueError('%s must be a string', str(value))
172
173 bValid = True # assume True
174 parts = value.split('.')
f54a36bb 175
c878ceea
RD
176 if len(parts) != 4:
177 bValid = False
178 else:
179 for i in range(4):
180 part = parts[i]
181 if not 0 <= len(part) <= 3:
182 bValid = False
183 break
184 elif part.strip(): # non-empty part
185 try:
186 j = string.atoi(part)
187 if not 0 <= j <= 255:
188 bValid = False
189 break
190 else:
191 parts[i] = '%3d' % j
192 except:
193 bValid = False
194 break
195 else:
196 # allow empty sections for SetValue (will result in "invalid" value,
197 # but this may be useful for initializing the control:
198 parts[i] = ' ' # convert empty field to 3-char length
199
200 if not bValid:
201## dbg(indent=0)
202 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))
203 else:
204## dbg('parts:', parts)
205 value = string.join(parts, '.')
206 BaseMaskedTextCtrl.SetValue(self, value)
207## dbg(indent=0)
208
f54a36bb
RD
209__i=0
210## CHANGELOG:
211## ====================
212## Version 1.2
213## 1. Fixed bugs involving missing imports now that these classes are in
214## their own module.
215## 2. Added doc strings for ePyDoc.
216## 3. Renamed helper functions, vars etc. not intended to be visible in public
217## interface to code.
218##
5f280eaa
RD
219## Version 1.1
220## Made ipaddrctrls allow right-insert in subfields, now that insert/cut/paste works better