File: mentryIPv6Addr.tcl

package info (click to toggle)
tklib 0.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 23,156 kB
  • sloc: tcl: 105,088; sh: 2,573; ansic: 792; pascal: 359; makefile: 69; sed: 53; exp: 21
file content (304 lines) | stat: -rw-r--r-- 8,527 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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#==============================================================================
# Contains the implementation of a multi-entry widget for IPv6 addresses.
#
# Copyright (c) 2009-2023  Csaba Nemethi (E-mail: csaba.nemethi@t-online.de)
#==============================================================================

#
# Namespace initialization
# ========================
#

namespace eval mentry {
    #
    # Define some bindings for the binding tag MentryIPv6Addr
    #
    bind MentryIPv6Addr <Up>	  { mentry::incrIPv6AddrComp %W  1 }
    bind MentryIPv6Addr <Down>	  { mentry::incrIPv6AddrComp %W -1 }
    bind MentryIPv6Addr <Prior>	  { mentry::incrIPv6AddrComp %W  10 }
    bind MentryIPv6Addr <Next>	  { mentry::incrIPv6AddrComp %W -10 }
    bind MentryIPv6Addr <<Paste>> { mentry::pasteIPv6Addr %W }
    variable winSys
    variable uniformWheelSupport
    if {$uniformWheelSupport} {
	bind MentryIPv6Addr <MouseWheel> {
	    mentry::incrIPv6AddrComp %W \
		[expr {%D > 0 ? (%D + 119) / 120 : %D / 120}]
	}
	bind MentryIPv6Addr <Option-MouseWheel> {
	    mentry::incrIPv6AddrComp %W \
		[expr {%D > 0 ? (%D + 11) / 12 : %D / 12}]
	}
	bind MentryIPv6Addr <Shift-MouseWheel> {
	    # Ignore the event
	}
    } elseif {$winSys eq "aqua"} {
	catch {
	    bind MentryIPv6Addr <MouseWheel> {
		mentry::incrIPv6AddrComp %W %D
	    }
	    bind MentryIPv6Addr <Option-MouseWheel> {
		mentry::incrIPv6AddrComp %W [expr {10 * %D}]
	    }
	    bind MentryIPv6Addr <Shift-MouseWheel> {
		# Ignore the event
	    }
	}
    } else {
	catch {
	    bind MentryIPv6Addr <MouseWheel> {
		mentry::incrIPv6AddrComp %W \
		    [expr {%D > 0 ? (%D + 11) / 12 : %D / 12}]
	    }
	    bind MentryIPv6Addr <Shift-MouseWheel> {
		# Ignore the event
	    }
	}

	if {$winSys eq "x11"} {
	    bind MentryIPv6Addr <Button-4> {
		if {!$tk_strictMotif} {
		    mentry::incrIPv6AddrComp %W 1
		}
	    }
	    bind MentryIPv6Addr <Button-5> {
		if {!$tk_strictMotif} {
		    mentry::incrIPv6AddrComp %W -1
		}
	    }
	    bind MentryIPv6Addr <Shift-Button-4> {
		# Ignore the event
	    }
	    bind MentryIPv6Addr <Shift-Button-5> {
		# Ignore the event
	    }
	}
    }
    variable touchpadScrollSupport
    if {$touchpadScrollSupport} {
	bind MentryIPv6Addr <TouchpadScroll> {
	    lassign [tk::PreciseScrollDeltas %D] mentry::dX mentry::dY
	    if {$mentry::dY != 0 && [expr {%# %% 12}] == 0} {
		mentry::incrIPv6AddrComp %W [expr {$mentry::dY > 0 ? -1 : 1}]
	    }
	}
    }
}

#
# Public procedures
# =================
#

#------------------------------------------------------------------------------
# mentry::ipv6AddrMentry
#
# Creates a new mentry widget win that allows to display and edit IPv6
# addresses.  Sets the type attribute of the widget to IPv6Addr and returns the
# name of the newly created widget.
#------------------------------------------------------------------------------
proc mentry::ipv6AddrMentry {win args} {
    #
    # Create the widget and set its type to IPv6Addr
    #
    eval [list mentry $win] $args
    ::$win configure -body {4 : 4 : 4 : 4 : 4 : 4 : 4 : 4}
    ::$win attrib type IPv6Addr

    #
    # In each entry component allow only hexadecimal digits, and
    # insert the binding tag MentryIPv6Addr in the list of
    # binding tags of the entry, just after its path name
    #
    for {set n 0} {$n < 8} {incr n} {
	set w [::$win entrypath $n]
	wcb::cbappend $w before insert wcb::convStrToLower \
		      {wcb::checkStrForRegExp {^[0-9a-fA-F]*$}}
	::$win adjustentry $n "0123456789abcdefABCDEF"
	bindtags $w [linsert [bindtags $w] 1 MentryIPv6Addr]
    }

    return $win
}

#------------------------------------------------------------------------------
# mentry::putIPv6Addr
#
# Outputs the IPv6 address addr to the mentry widget win of type IPv6Addr.
#------------------------------------------------------------------------------
proc mentry::putIPv6Addr {addr win} {
    set errorMsg "expected an IPv6 address but got \"$addr\""

    #
    # Check the syntax of addr
    #
    if {[string match "*::*::*" $addr] || [string match "*:::*" $addr] ||
	[regexp {^:[^:]} $addr] || [regexp {[^:]:$} $addr]} {
	return -code error $errorMsg
    }

    #
    # Split addr on colons; make sure that a starting or
    # trailing "::" will give rise to a single empty string
    #
    if {$addr eq "::"} {
	set lst [list ""]
    } elseif {[regexp {^::(.+)} $addr dummy var]} {
	set lst [list ""]
	eval lappend lst [split $var ":"]
    } elseif {[regexp {(.+)::$} $addr dummy var]} {
	set lst [split $var ":"]
	lappend lst ""
    } else {
	set lst [split $addr ":"]
    }

    #
    # Replace the unique empty element of the list
    # (if any) with an appropriate number of zeros
    #
    set emptyIdx [lsearch -exact $lst ""]
    set lstLen [llength $lst]
    if {$emptyIdx < 0} {
	if {$lstLen != 8} {
	    return -code error $errorMsg
	}
    } else {
	if {$lstLen > 8} {
	    return -code error $errorMsg
	}

	set count [expr {9 - $lstLen}]
	for {set n 0} {$n < $count} {incr n} {
	    lappend lst2 0
	}
	set lst [eval lreplace {$lst} $emptyIdx $emptyIdx $lst2]
    }

    #
    # Try to convert the 8 elements of the list to hexadecimal
    # strings and check whether they are in the range 0 - 65535
    #
    for {set n 0} {$n < 8} {incr n} {
	set val 0x[lindex $lst $n]
	##nagelfar ignore
	if {[catch {format "%x" $val} str$n] != 0 | $val > 65535} {
	    return -code error $errorMsg
	}
    }

    checkIfIPv6AddrMentry $win
    ::$win put 0 $str0 $str1 $str2 $str3 $str4 $str5 $str6 $str7
}

#------------------------------------------------------------------------------
# mentry::getIPv6Addr
#
# Returns the IPv6 address contained in the mentry widget win of type IPv6Addr.
#------------------------------------------------------------------------------
proc mentry::getIPv6Addr win {
    checkIfIPv6AddrMentry $win

    #
    # Generate an error if any entry component is empty
    #
    for {set n 0} {$n < 8} {incr n} {
	if {[::$win isempty $n]} {
	    focus [::$win entrypath $n]
	    return -code error EMPTY
	}
    }

    ::$win getarray strs
    ##nagelfar ignore
    return [format "%x:%x:%x:%x:%x:%x:%x:%x" \
	    0x$strs(0) 0x$strs(1) 0x$strs(2) 0x$strs(3) \
	    0x$strs(4) 0x$strs(5) 0x$strs(6) 0x$strs(7)]
}

#
# Private procedures
# ==================
#

#------------------------------------------------------------------------------
# mentry::checkIfIPv6AddrMentry
#
# Generates an error if win is not a mentry widget of type IPv6Addr.
#------------------------------------------------------------------------------
proc mentry::checkIfIPv6AddrMentry win {
    if {![winfo exists $win]} {
	return -code error "bad window path name \"$win\""
    }

    if {[winfo class $win] ne "Mentry" || [::$win attrib type] ne "IPv6Addr"} {
	return -code error \
	       "window \"$win\" is not a mentry widget for IPv6 addresses"
    }
}

#------------------------------------------------------------------------------
# mentry::incrIPv6AddrComp
#
# This procedure handles <Up>, <Down>, <Prior>, and <Next> events in the entry
# component w of a mentry widget for IPv6 addresses.  It increments the entry's
# value by the specified amount if allowed.
#------------------------------------------------------------------------------
proc mentry::incrIPv6AddrComp {w amount} {
    set str [$w get]
    if {$str eq ""} {
	#
	# Insert a "0"
	#
	_$w insert end 0
	_$w icursor 0
    } else {
	#
	# Increment the entry's value by the given amount if allowed
	#
	##nagelfar ignore
	scan $str "%x" val
	if {$amount > 0} {
	    if {$val < 65535} {
		incr val $amount
		if {$val > 65535} {
		    set val 65535
		}
	    } else {
		return ""
	    }
	} else {
	    if {$val > 0} {
		incr val $amount
		if {$val < 0} {
		    set val 0
		}
	    } else {
		return ""
	    }
	}
	##nagelfar ignore
	set str [format "%x" $val]
	set oldPos [$w index insert]
	_$w delete 0 end
	_$w insert end $str
	_$w icursor $oldPos
    }
}

#------------------------------------------------------------------------------
# mentry::pasteIPv6Addr
#
# This procedure handles <<Paste>> events in the entry component w of a mentry
# widget for IPv6 addresses by pasting the current contents of the clipboard
# into the mentry if it is a valid IPv6 address.
#------------------------------------------------------------------------------
proc mentry::pasteIPv6Addr w {
    set res [catch {::tk::GetSelection $w CLIPBOARD} addr]
    if {$res == 0} {
	parseChildPath $w win n
	catch { putIPv6Addr $addr $win }
    }

    return -code break ""
}