Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / src / nas,5.n2.os.2 / lib / python / lib / python2.4 / site-packages / Pmw / Pmw_1_2 / lib / PmwEntryField.py
CommitLineData
86530b38
AT
1# Based on iwidgets2.2.0/entryfield.itk code.
2
3import re
4import string
5import types
6import Tkinter
7import Pmw
8
9# Possible return values of validation functions.
10OK = 1
11ERROR = 0
12PARTIAL = -1
13
14class EntryField(Pmw.MegaWidget):
15 _classBindingsDefinedFor = 0
16
17 def __init__(self, parent = None, **kw):
18
19 # Define the megawidget options.
20 INITOPT = Pmw.INITOPT
21 optiondefs = (
22 ('command', None, None),
23 ('errorbackground', 'pink', None),
24 ('invalidcommand', self.bell, None),
25 ('labelmargin', 0, INITOPT),
26 ('labelpos', None, INITOPT),
27 ('modifiedcommand', None, None),
28 ('sticky', 'ew', INITOPT),
29 ('validate', None, self._validate),
30 ('extravalidators', {}, None),
31 ('value', '', INITOPT),
32 )
33 self.defineoptions(kw, optiondefs)
34
35 # Initialise the base class (after defining the options).
36 Pmw.MegaWidget.__init__(self, parent)
37
38 # Create the components.
39 interior = self.interior()
40 self._entryFieldEntry = self.createcomponent('entry',
41 (), None,
42 Tkinter.Entry, (interior,))
43 self._entryFieldEntry.grid(column=2, row=2, sticky=self['sticky'])
44 if self['value'] != '':
45 self.__setEntry(self['value'])
46 interior.grid_columnconfigure(2, weight=1)
47 interior.grid_rowconfigure(2, weight=1)
48
49 self.createlabel(interior)
50
51 # Initialise instance variables.
52
53 self.normalBackground = None
54 self._previousText = None
55
56 # Initialise instance.
57
58 _registerEntryField(self._entryFieldEntry, self)
59
60 # Establish the special class bindings if not already done.
61 # Also create bindings if the Tkinter default interpreter has
62 # changed. Use Tkinter._default_root to create class
63 # bindings, so that a reference to root is created by
64 # bind_class rather than a reference to self, which would
65 # prevent object cleanup.
66 if EntryField._classBindingsDefinedFor != Tkinter._default_root:
67 tagList = self._entryFieldEntry.bindtags()
68 root = Tkinter._default_root
69
70 allSequences = {}
71 for tag in tagList:
72
73 sequences = root.bind_class(tag)
74 if type(sequences) is types.StringType:
75 # In old versions of Tkinter, bind_class returns a string
76 sequences = root.tk.splitlist(sequences)
77
78 for sequence in sequences:
79 allSequences[sequence] = None
80 for sequence in allSequences.keys():
81 root.bind_class('EntryFieldPre', sequence, _preProcess)
82 root.bind_class('EntryFieldPost', sequence, _postProcess)
83
84 EntryField._classBindingsDefinedFor = root
85
86 self._entryFieldEntry.bindtags(('EntryFieldPre',) +
87 self._entryFieldEntry.bindtags() + ('EntryFieldPost',))
88 self._entryFieldEntry.bind('<Return>', self._executeCommand)
89
90 # Check keywords and initialise options.
91 self.initialiseoptions()
92
93 def destroy(self):
94 _deregisterEntryField(self._entryFieldEntry)
95 Pmw.MegaWidget.destroy(self)
96
97 def _getValidatorFunc(self, validator, index):
98 # Search the extra and standard validator lists for the
99 # given 'validator'. If 'validator' is an alias, then
100 # continue the search using the alias. Make sure that
101 # self-referencial aliases do not cause infinite loops.
102
103 extraValidators = self['extravalidators']
104 traversedValidators = []
105
106 while 1:
107 traversedValidators.append(validator)
108 if extraValidators.has_key(validator):
109 validator = extraValidators[validator][index]
110 elif _standardValidators.has_key(validator):
111 validator = _standardValidators[validator][index]
112 else:
113 return validator
114 if validator in traversedValidators:
115 return validator
116
117 def _validate(self):
118 dict = {
119 'validator' : None,
120 'min' : None,
121 'max' : None,
122 'minstrict' : 1,
123 'maxstrict' : 1,
124 }
125 opt = self['validate']
126 if type(opt) is types.DictionaryType:
127 dict.update(opt)
128 else:
129 dict['validator'] = opt
130
131 # Look up validator maps and replace 'validator' field with
132 # the corresponding function.
133 validator = dict['validator']
134 valFunction = self._getValidatorFunc(validator, 0)
135 self._checkValidateFunction(valFunction, 'validate', validator)
136 dict['validator'] = valFunction
137
138 # Look up validator maps and replace 'stringtovalue' field
139 # with the corresponding function.
140 if dict.has_key('stringtovalue'):
141 stringtovalue = dict['stringtovalue']
142 strFunction = self._getValidatorFunc(stringtovalue, 1)
143 self._checkValidateFunction(
144 strFunction, 'stringtovalue', stringtovalue)
145 else:
146 strFunction = self._getValidatorFunc(validator, 1)
147 if strFunction == validator:
148 strFunction = len
149 dict['stringtovalue'] = strFunction
150
151 self._validationInfo = dict
152 args = dict.copy()
153 del args['validator']
154 del args['min']
155 del args['max']
156 del args['minstrict']
157 del args['maxstrict']
158 del args['stringtovalue']
159 self._validationArgs = args
160 self._previousText = None
161
162 if type(dict['min']) == types.StringType and strFunction is not None:
163 dict['min'] = apply(strFunction, (dict['min'],), args)
164 if type(dict['max']) == types.StringType and strFunction is not None:
165 dict['max'] = apply(strFunction, (dict['max'],), args)
166
167 self._checkValidity()
168
169 def _checkValidateFunction(self, function, option, validator):
170 # Raise an error if 'function' is not a function or None.
171
172 if function is not None and not callable(function):
173 extraValidators = self['extravalidators']
174 extra = extraValidators.keys()
175 extra.sort()
176 extra = tuple(extra)
177 standard = _standardValidators.keys()
178 standard.sort()
179 standard = tuple(standard)
180 msg = 'bad %s value "%s": must be a function or one of ' \
181 'the standard validators %s or extra validators %s'
182 raise ValueError, msg % (option, validator, standard, extra)
183
184 def _executeCommand(self, event = None):
185 cmd = self['command']
186 if callable(cmd):
187 if event is None:
188 # Return result of command for invoke() method.
189 return cmd()
190 else:
191 cmd()
192
193 def _preProcess(self):
194
195 self._previousText = self._entryFieldEntry.get()
196 self._previousICursor = self._entryFieldEntry.index('insert')
197 self._previousXview = self._entryFieldEntry.index('@0')
198 if self._entryFieldEntry.selection_present():
199 self._previousSel= (self._entryFieldEntry.index('sel.first'),
200 self._entryFieldEntry.index('sel.last'))
201 else:
202 self._previousSel = None
203
204 def _postProcess(self):
205
206 # No need to check if text has not changed.
207 previousText = self._previousText
208 if previousText == self._entryFieldEntry.get():
209 return self.valid()
210
211 valid = self._checkValidity()
212 if self.hulldestroyed():
213 # The invalidcommand called by _checkValidity() destroyed us.
214 return valid
215
216 cmd = self['modifiedcommand']
217 if callable(cmd) and previousText != self._entryFieldEntry.get():
218 cmd()
219 return valid
220
221 def checkentry(self):
222 # If there is a variable specified by the entry_textvariable
223 # option, checkentry() should be called after the set() method
224 # of the variable is called.
225
226 self._previousText = None
227 return self._postProcess()
228
229 def _getValidity(self):
230 text = self._entryFieldEntry.get()
231 dict = self._validationInfo
232 args = self._validationArgs
233
234 if dict['validator'] is not None:
235 status = apply(dict['validator'], (text,), args)
236 if status != OK:
237 return status
238
239 # Check for out of (min, max) range.
240 if dict['stringtovalue'] is not None:
241 min = dict['min']
242 max = dict['max']
243 if min is None and max is None:
244 return OK
245 val = apply(dict['stringtovalue'], (text,), args)
246 if min is not None and val < min:
247 if dict['minstrict']:
248 return ERROR
249 else:
250 return PARTIAL
251 if max is not None and val > max:
252 if dict['maxstrict']:
253 return ERROR
254 else:
255 return PARTIAL
256 return OK
257
258 def _checkValidity(self):
259 valid = self._getValidity()
260 oldValidity = valid
261
262 if valid == ERROR:
263 # The entry is invalid.
264 cmd = self['invalidcommand']
265 if callable(cmd):
266 cmd()
267 if self.hulldestroyed():
268 # The invalidcommand destroyed us.
269 return oldValidity
270
271 # Restore the entry to its previous value.
272 if self._previousText is not None:
273 self.__setEntry(self._previousText)
274 self._entryFieldEntry.icursor(self._previousICursor)
275 self._entryFieldEntry.xview(self._previousXview)
276 if self._previousSel is not None:
277 self._entryFieldEntry.selection_range(self._previousSel[0],
278 self._previousSel[1])
279
280 # Check if the saved text is valid as well.
281 valid = self._getValidity()
282
283 self._valid = valid
284
285 if self.hulldestroyed():
286 # The validator or stringtovalue commands called by
287 # _checkValidity() destroyed us.
288 return oldValidity
289
290 if valid == OK:
291 if self.normalBackground is not None:
292 self._entryFieldEntry.configure(
293 background = self.normalBackground)
294 self.normalBackground = None
295 else:
296 if self.normalBackground is None:
297 self.normalBackground = self._entryFieldEntry.cget('background')
298 self._entryFieldEntry.configure(
299 background = self['errorbackground'])
300
301 return oldValidity
302
303 def invoke(self):
304 return self._executeCommand()
305
306 def valid(self):
307 return self._valid == OK
308
309 def clear(self):
310 self.setentry('')
311
312 def __setEntry(self, text):
313 oldState = str(self._entryFieldEntry.cget('state'))
314 if oldState != 'normal':
315 self._entryFieldEntry.configure(state='normal')
316 self._entryFieldEntry.delete(0, 'end')
317 self._entryFieldEntry.insert(0, text)
318 if oldState != 'normal':
319 self._entryFieldEntry.configure(state=oldState)
320
321 def setentry(self, text):
322 self._preProcess()
323 self.__setEntry(text)
324 return self._postProcess()
325
326 def getvalue(self):
327 return self._entryFieldEntry.get()
328
329 def setvalue(self, text):
330 return self.setentry(text)
331
332Pmw.forwardmethods(EntryField, Tkinter.Entry, '_entryFieldEntry')
333
334# ======================================================================
335
336
337# Entry field validation functions
338
339_numericregex = re.compile('^[0-9]*$')
340_alphabeticregex = re.compile('^[a-z]*$', re.IGNORECASE)
341_alphanumericregex = re.compile('^[0-9a-z]*$', re.IGNORECASE)
342
343def numericvalidator(text):
344 if text == '':
345 return PARTIAL
346 else:
347 if _numericregex.match(text) is None:
348 return ERROR
349 else:
350 return OK
351
352def integervalidator(text):
353 if text in ('', '-', '+'):
354 return PARTIAL
355 try:
356 string.atol(text)
357 return OK
358 except ValueError:
359 return ERROR
360
361def alphabeticvalidator(text):
362 if _alphabeticregex.match(text) is None:
363 return ERROR
364 else:
365 return OK
366
367def alphanumericvalidator(text):
368 if _alphanumericregex.match(text) is None:
369 return ERROR
370 else:
371 return OK
372
373def hexadecimalvalidator(text):
374 if text in ('', '0x', '0X', '+', '+0x', '+0X', '-', '-0x', '-0X'):
375 return PARTIAL
376 try:
377 string.atol(text, 16)
378 return OK
379 except ValueError:
380 return ERROR
381
382def realvalidator(text, separator = '.'):
383 if separator != '.':
384 if string.find(text, '.') >= 0:
385 return ERROR
386 index = string.find(text, separator)
387 if index >= 0:
388 text = text[:index] + '.' + text[index + 1:]
389 try:
390 string.atof(text)
391 return OK
392 except ValueError:
393 # Check if the string could be made valid by appending a digit
394 # eg ('-', '+', '.', '-.', '+.', '1.23e', '1E-').
395 if len(text) == 0:
396 return PARTIAL
397 if text[-1] in string.digits:
398 return ERROR
399 try:
400 string.atof(text + '0')
401 return PARTIAL
402 except ValueError:
403 return ERROR
404
405def timevalidator(text, separator = ':'):
406 try:
407 Pmw.timestringtoseconds(text, separator)
408 return OK
409 except ValueError:
410 if len(text) > 0 and text[0] in ('+', '-'):
411 text = text[1:]
412 if re.search('[^0-9' + separator + ']', text) is not None:
413 return ERROR
414 return PARTIAL
415
416def datevalidator(text, format = 'ymd', separator = '/'):
417 try:
418 Pmw.datestringtojdn(text, format, separator)
419 return OK
420 except ValueError:
421 if re.search('[^0-9' + separator + ']', text) is not None:
422 return ERROR
423 return PARTIAL
424
425_standardValidators = {
426 'numeric' : (numericvalidator, string.atol),
427 'integer' : (integervalidator, string.atol),
428 'hexadecimal' : (hexadecimalvalidator, lambda s: string.atol(s, 16)),
429 'real' : (realvalidator, Pmw.stringtoreal),
430 'alphabetic' : (alphabeticvalidator, len),
431 'alphanumeric' : (alphanumericvalidator, len),
432 'time' : (timevalidator, Pmw.timestringtoseconds),
433 'date' : (datevalidator, Pmw.datestringtojdn),
434}
435
436_entryCache = {}
437
438def _registerEntryField(entry, entryField):
439 # Register an EntryField widget for an Entry widget
440
441 _entryCache[entry] = entryField
442
443def _deregisterEntryField(entry):
444 # Deregister an Entry widget
445 del _entryCache[entry]
446
447def _preProcess(event):
448 # Forward preprocess events for an Entry to it's EntryField
449
450 _entryCache[event.widget]._preProcess()
451
452def _postProcess(event):
453 # Forward postprocess events for an Entry to it's EntryField
454
455 # The function specified by the 'command' option may have destroyed
456 # the megawidget in a binding earlier in bindtags, so need to check.
457 if _entryCache.has_key(event.widget):
458 _entryCache[event.widget]._postProcess()