File: ipaddrctrl.py

package info (click to toggle)
wxpython4.0 4.2.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 232,540 kB
  • sloc: cpp: 958,937; python: 233,059; ansic: 150,441; makefile: 51,662; sh: 8,687; perl: 1,563; javascript: 584; php: 326; xml: 200
file content (242 lines) | stat: -rw-r--r-- 9,158 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#----------------------------------------------------------------------------
# Name:         masked.ipaddrctrl.py
# Authors:      Will Sadkin
# Email:        wsadkin@nameconnector.com
# Created:      02/11/2003
# Copyright:    (c) 2003 by Will Sadkin, 2003
# License:      wxWidgets license
#
# Tags:        phoenix-port, py3-port, unittest, documented
#
#----------------------------------------------------------------------------
# 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.
#
#----------------------------------------------------------------------------
"""
Provides a smart text input control that understands the structure and
limits of IP Addresses, and allows automatic field navigation as the
user hits '.' when typing.
"""

import  wx
import  six
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:
    """
    Defines 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,
                  **kwargs):

        """
        Default class constructor.

        :param wx.Window `parent`: the window parent. Must not be ``None``;
        :param integer `id`: window identifier. A value of -1 indicates a default value;
        :param string `value`: value to be shown;
        :param `pos`: the control position. A value of (-1, -1) indicates a default position,
         chosen by either the windowing system or wxPython, depending on platform;
        :type `pos`: tuple or :class:`wx.Point`
        :param `size`: the control size. A value of (-1, -1) indicates a default size,
         chosen by either the windowing system or wxPython, depending on platform;
        :param integer `style`: the window style;
        :param wx.Validator `validator`: this is mainly provided for data-transfer, as control does
          its own validation;
        :param string `name`: the window name;
        :param boolean `setupEventHandling`: setup event handling by default.

        """

        if 'mask' not in kwargs:
            kwargs['mask'] = mask = "###.###.###.###"
        if 'formatcodes' not in kwargs:
            kwargs['formatcodes'] = 'F_Sr<>'
        if 'validRegex' not in kwargs:
            kwargs['validRegex'] = r"(  \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'] = r"(   |  \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):
        """
        Defines what action to take when the '.' character is typed in the
        control.  By default, the current field is right-justified, and the
        cursor is placed in the next field.
        """
##        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 delimiter; (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):
        """
        Returns the control value, with any spaces removed.
        """
        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):
        """
        Takes a string value, validates it for a valid IP address,
        splits it into an array of 4 fields, justifies it
        appropriately, and inserts it into the control.
        Invalid values will raise a ValueError exception.

        :param string `value`: the IP address in the form '000.000.000.000'

        """
##        dbg('IpAddrCtrl::SetValue(%s)' % str(value), indent=1)
        if not isinstance(value, six.string_types):
##            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 = int(part)
                        if not 0 <= j <= 255:
                            bValid = False
                            break
                        else:
                            parts[i] = '%3d' % j
                    except Exception:
                        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 = '.'.join(parts)
            BaseMaskedTextCtrl.SetValue(self, value)
##        dbg(indent=0)

__i=0
## CHANGELOG:
## ====================
##  Version 1.2
##  1. Fixed bugs involving missing imports now that these classes are in
##     their own module.
##  2. Added doc strings for ePyDoc.
##  3. Renamed helper functions, vars etc. not intended to be visible in public
##     interface to code.
##
## Version 1.1
##  Made ipaddrctrls allow right-insert in subfields, now that insert/cut/paste works better