Attachment 'ObjectAttrValidator2.py'

Download

   1 #	ObjectAttrValidator.py
   2 #
   3 #	------------------------------------------------------------
   4 #	Copyright 2004 by Samuel Reynolds. All rights reserved.
   5 #
   6 #	Permission to use, copy, modify, and distribute this software and its
   7 #	documentation for any purpose and without fee is hereby granted,
   8 #	provided that the above copyright notice appear in all copies and that
   9 #	both that copyright notice and this permission notice appear in
  10 #	supporting documentation, and that the name of Samuel Reynolds
  11 #	not be used in advertising or publicity pertaining to distribution
  12 #	of the software without specific, written prior permission.
  13 #
  14 #	SAMUEL REYNOLDS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15 #	INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
  16 #	EVENT SHALL SAMUEL REYNOLDS BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
  17 #	CONSEQUENTIAL DAMAGES, OR FOR ANY DAMAGES WHATSOEVER RESULTING FROM
  18 #	LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  19 #	NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20 #	WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21 #	------------------------------------------------------------
  22 
  23 import wx
  24 
  25 class ObjectAttrValidator( wx.PyValidator ):
  26 	"""
  27 	Base class for validators that validate *attributes* of
  28 	objects and provide two-way data transfer between those
  29 	attributes and UI controls.
  30 	
  31 	ObjectAttrValidator has no knowledge of the specific
  32 	type of widget to be validated. Responsibility for
  33 	interacting with specific types of widgets is delegated
  34 	to subclasses.
  35 	
  36 	Subclasses must implement the following methods:
  37 		* _setControlValue( self, value )
  38 				Set the value of control to the value provided.
  39 		* _getControlValue( self )
  40 				Return the value of control.
  41 	Remaining logic is implemented in ObjectAttrValidator.
  42 	
  43 	
  44 	CHAMELEON POWERS:
  45 	
  46 	To simplify use in an object-editor context (in which
  47 	a single editor GUI is used to edit multiple objects
  48 	of the same type), ObjectAttrValidator allows changing
  49 	objects on the fly.
  50 	
  51 	For example, if references to field widgets are stored
  52 	in a list self._fieldWidgets, the editor class could
  53 	implement the following methods:
  54 		
  55 		def SetObject( self, editObject ):
  56 			'Set object for editing.'
  57 			self._editObject = editObject
  58 			self._updateValidators()
  59 			self.TransferDataToWindow()
  60 		
  61 		def _updateValidators( self ):
  62 			for wgt in self._fieldWidgets:
  63 				validator = wgt.GetValidator()
  64 				validator.SetObject( self._editObject )
  65 	
  66 	
  67 	FORMATTERS
  68 	
  69 	ObjectAttrValidator uses Formatters for validation and
  70 	two-way reformatting. A Formatter is aware of source data type,
  71 	and handles translation between presentation representation and
  72 	storage representation.
  73 	
  74 	A Formatter must provide the following interface methods:
  75 		* format( stored_value )
  76 				Format a value for presentation.
  77 		* coerce( presentation_value )
  78 				Convert a presentation-formatted value
  79 				to a storage-formatted value (may include
  80 				type conversion such as string->integer).
  81 		* validate( presentation_value )
  82 				Validate a presentation-formatted value.
  83 				Return True if valid or False if invalid.
  84 	
  85 	If a formatter is assigned, the ObjectAttrValidator
  86 	will call the formatter's format, coerce, and validate
  87 	methods at appropriate points in its processing.
  88 	
  89 	With a formatter, there is no need of, for example,
  90 	integer-aware entry fields. The formatter handles
  91 	validation and conversion of the input value.
  92 	"""
  93 	
  94 	def __init__( self, obj, attrName, formatter=None, flRequired=True, validationCB=None ):
  95 		super(ObjectAttrValidator,self).__init__()
  96 		
  97 		self.obj          = obj
  98 		self.attrName     = attrName
  99 		self.flRequired   = flRequired
 100 		self.formatter    = formatter
 101 		self.validationCB = validationCB
 102 	
 103 	
 104 	def Clone( self ):
 105 		"""
 106 		Return a new validator for the same field of the same object.
 107 		"""
 108 		return self.__class__( self.obj, self.attrName, self.formatter,
 109 				self.flRequired, self.validationCB )
 110 	
 111 	
 112 	def SetObject( self, obj ):
 113 		"""
 114 		Set or change the object with which the validator interacts.
 115 		
 116 		Useful for changing objects when a single panel is used
 117 		to edit a number of identical objects.
 118 		"""
 119 		self.obj = obj
 120 	
 121 	
 122 	def TransferToWindow( self ):
 123 		"""
 124 		Transfer data from validator to window.
 125 		
 126 		Delegates actual writing to destination widget to subclass
 127 		via _setControlValue method.
 128 		"""
 129 		if self.obj == None:
 130 			# Nothing to do
 131 			return True
 132 		
 133 		# Copy object attribute value to widget
 134 		val = getattr( self.obj, self.attrName )
 135 		if val == None:
 136 			val = ''
 137 		if self.formatter:
 138 			val = self.formatter.format( val )
 139 		self._setControlValue( val )
 140 		
 141 		return True
 142 	
 143 	
 144 	def TransferFromWindow( self ):
 145 		"""
 146 		Transfer data from window to validator.
 147 		
 148 		Delegates actual reading from destination widget to subclass
 149 		via _getControlValue method.
 150 		
 151 		Only copies data if value is actually changed from attribute value.
 152 		"""
 153 		if self.obj == None:
 154 			# Nothing to do
 155 			return True
 156 		
 157 		# Get widget value
 158 		val = self._getControlValue()
 159 		
 160 		# Check widget value against attribute value; only copy if changed
 161 		# Get object attribute value
 162 		oldVal = getattr( self.obj, self.attrName )
 163 		if self.formatter:
 164 			oldVal = self.formatter.format( oldVal )
 165 		if val != oldVal:
 166 			if self.formatter:
 167 				val = self.formatter.coerce( val )
 168 			setattr( self.obj, self.attrName, val )
 169 		
 170 		return True
 171 	
 172 	
 173 	def Validate( self, win ):
 174 		"""
 175 		Validate the contents of the given control.
 176 		
 177 		Default behavior: Anything goes.
 178 		"""
 179 		flValid = True
 180 		val = self._getControlValue()
 181 		if self.flRequired and val == '':
 182 			flValid = False
 183 		if flValid and self.formatter:
 184 			flValid = self.formatter.validate( val )
 185 		if self.validationCB:
 186 			self.validationCB( self.obj, self.attrName, val, self.flRequired, flValid )
 187 		return flValid
 188 	
 189 	
 190 	def _setControlValue( self, value ):
 191 		"""
 192 		Set the value of the target control.
 193 		
 194 		Subclass must implement.
 195 		"""
 196 		raise NotImplementedError, 'Subclass must implement _setControlValue'
 197 	
 198 	
 199 	def _getControlValue( self ):
 200 		"""
 201 		Return the value from the target control.
 202 		
 203 		Subclass must implement.
 204 		"""
 205 		raise NotImplementedError, 'Subclass must implement _getControlValue'
 206 
 207 
 208 class ObjectAttrTextValidator( ObjectAttrValidator ):
 209 	"""
 210 	Validator for TextCtrl widgets.
 211 	"""
 212 	def __init__( self, *args, **kwargs ):
 213 		""" Standard constructor. """
 214 		super(ObjectAttrTextValidator,self).__init__( *args, **kwargs )
 215 	
 216 	
 217 	def TransferToWindow( self ):
 218 		"""
 219 		Transfer data from validator to window.
 220 		
 221 		Delegates actual writing to destination widget to subclass
 222 		via _setControlValue method.
 223 		"""
 224 		if self.obj == None:
 225 			# Clear the widget
 226 			wgt = self.GetWindow()
 227 			wgt.Clear()
 228 			return True
 229 		
 230 		# Default behavior otherwise
 231 		return super(ObjectAttrTextValidator,self).TransferToWindow()
 232 	
 233 	
 234 	def _setControlValue( self, value ):
 235 		"""
 236 		Set the value of the TextCtrl.
 237 		"""
 238 		wgt = self.GetWindow()
 239 		wgt.SetValue( value )
 240 	
 241 	
 242 	def _getControlValue( self ):
 243 		"""
 244 		Return the value from the TextCtrl.
 245 		"""
 246 		wgt = self.GetWindow()
 247 		return wgt.GetValue()
 248 
 249 
 250 class ObjectAttrSelectorValidator( ObjectAttrValidator ):
 251 	"""
 252 	Validator for ControlWithItems widgets (ListBox, Choice).
 253 	
 254 	For wx.ListBox, assumes single-selection mode (wx.LB_SINGLE).
 255 	"""
 256 	def __init__( self, obj, attrName, formatter, *args, **kwargs ):
 257 		""" Standard constructor. """
 258 		super(ObjectAttrSelectorValidator,self).__init__(
 259 				obj, attrName, formatter, *args, **kwargs )
 260 	
 261 	
 262 	def _getFieldOptions( self, name ):
 263 		"""
 264 		Return list of (id,label) pairs.
 265 		"""
 266 		return self.formatter.validValues()
 267 	
 268 	
 269 	def _setControlValue( self, value ):
 270 		"""
 271 		Set the value *and the options* of the control.
 272 		By the time this is called, the value is already mapped for display.
 273 		"""
 274 		wgt = self.GetWindow()
 275 		
 276 		# Get options (list of (id,value) pairs)
 277 		options = self._getFieldOptions( self.attrName )
 278 		# Sort alphabetically
 279 		options = [ (opt[1], opt) for opt in options ]
 280 		options.sort()
 281 		options = [ opt[1] for opt in options ]
 282 		# Replace selector contents
 283 		wgt.Clear()
 284 		for id, label in options:
 285 			wgt.Append( label, id )
 286 		
 287 		# Set selection
 288 		wgt.SetStringSelection( value )
 289 	
 290 	
 291 	def _getControlValue( self ):
 292 		"""
 293 		Return the value from the TextCtrl.
 294 		"""
 295 		wgt = self.GetWindow()
 296 		return wgt.GetStringSelection()
 297 
 298 
 299 class ObjectAttrCheckListBoxValidator( ObjectAttrValidator ):
 300 	"""
 301 	Validator for CheckListBox widgets.
 302 	"""
 303 	def __init__( self, obj, attrName, formatter, *args, **kwargs ):
 304 		""" Standard constructor. """
 305 		super(ObjectAttrCheckListBoxValidator,self).__init__(
 306 				obj, attrName, formatter, *args, **kwargs )
 307 	
 308 	
 309 	########## REQUIRED INTERFACE ##########
 310 	
 311 	def _getFieldOptions( self, name ):
 312 		"""
 313 		Return list of (id,label) pairs.
 314 		"""
 315 		return self.formatter.validValues()
 316 	
 317 	
 318 	def _setControlValue( self, value ):
 319 		"""
 320 		Set the value *and the options* of the control.
 321 		By the time this is called, the value is already mapped for display.
 322 		
 323 		@param value:	Sequence of (value, label) pairs.
 324 		"""
 325 		wgt = self.GetWindow()
 326 		
 327 		# Get options (list of (id,value) pairs)
 328 		options = self._getFieldOptions( self.attrName )
 329 		# Sort alphabetically
 330 		options = [ (opt[1], opt) for opt in options ]
 331 		options.sort()
 332 		options = [ opt[1] for opt in options ]
 333 		# Replace selector contents
 334 		self._setControlOptions( options )
 335 		
 336 		# Set selection
 337 		wgt._setControlSelections( value )
 338 	
 339 	
 340 	def _getControlValue( self ):
 341 		"""
 342 		Return the value from the TextCtrl.
 343 		
 344 		Returns a list of client data values (not row indices).
 345 		"""
 346 		wgt = self.GetWindow()
 347 		selections = wgt.GetStringSelections()
 348 		value = [ wgt.GetClientData( idx ) for idx in selections ]
 349 		return value
 350 	
 351 	
 352 	########## END REQUIRED INTERFACE ##########
 353 	
 354 	
 355 	def _setControlOptions( self, options ):
 356 		"""
 357 		Set up or update control options.
 358 		
 359 		@param options:	Sequence of (id,label) pairs.
 360 		"""
 361 		wgt = self.GetWindow()
 362 		wgt.Clear()
 363 		for id, label in options:
 364 			wgt.Append( label, id )
 365 	
 366 	
 367 	def _setControlSelections( self, value ):
 368 		"""
 369 		Select the specified items in the control, and unselect others.
 370 		
 371 		@param value:	Integer or sequence of integers representing
 372 						the data value(s) of item(s) to be selected.
 373 						
 374 						If None or empty sequence, all currently-selected
 375 						items will be deselected.
 376 						
 377 						Any items in value that are not found in the
 378 						control have no effect.
 379 		"""
 380 		if value == None:
 381 			value = tuple()
 382 		elif not isinstance(value,(list,tuple)):
 383 			value = ( value, )
 384 		
 385 		numItems = wgt.GetCount()
 386 		for idx in xrange( 0, numItems ):
 387 			itemData = wgt.GetClientData( idx )
 388 			if itemData in value:
 389 				if not wgt.IsChecked( idx ):
 390 					wgt.Check( idx, True )
 391 			else:
 392 				if wgt.IsChecked( idx ):
 393 					wgt.Check( idx, False )
 394 
 395 
 396 class ObjectAttrRadioBoxValidator( ObjectAttrValidator ):
 397 	"""
 398 	Validator for RadioBox widgets.
 399 	"""
 400 	def __init__( self, obj, attrName, formatter, *args, **kwargs ):
 401 		""" Standard constructor. """
 402 		super(ObjectAttrRadioBoxValidator,self).__init__(
 403 				obj, attrName, formatter, *args, **kwargs )
 404 	
 405 	
 406 	def _setControlValue( self, value ):
 407 		"""
 408 		Set the value *and the options* of the control.
 409 		By the time this is called, the value is already mapped for display.
 410 		"""
 411 		wgt = self.GetWindow()
 412 		wgt.SetStringSelection( value )
 413 	
 414 	
 415 	def _getControlValue( self ):
 416 		"""
 417 		Return the value from the TextCtrl.
 418 		"""
 419 		wgt = self.GetWindow()
 420 		return wgt.GetStringSelection()

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2009-10-04 09:16:02, 11.6 KB) [[attachment:ObjectAttrValidator2.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.