[Zope-dev] Adding your own (complex) data types to property pages: example a nd problems... nd problems...

Mike Fletcher mfletch@tpresence.com
Thu, 4 May 2000 13:18:27 -0400


It is often necessary to have slightly more complex data types on your
Z-Class-like products.  For instance, in my current project, I need to be
able to set VRML-style vectors (particularly colors and three-element float
vectors).  Zope allows for creating converters fairly easily, so that you
can register code for interpreting data types.  However, Zope handles the
creation of input fields for property pages through a hard-coded
if/elif/else mechanism in OFS/properties.dtml . The result is that your
non-standard datatype shows up as "Unrecognized field type" and will not be
part of the form when submitted (which will often cause logic errors if (as
is likely) it is a required property).

Of course, it is possible to create custom manage documents for each
property page which has more advanced data types, but this almost completely
obviates the value of using property pages (i.e. automatic management of
property sets such that the programmer need not even consider the management
interface).

As of yet, I don't see a clean way of fixing this problem other than
re-writing properties.dtml to call out to an extensible mechanism for
generating edit fields.  To make this ideal, you would allow, for instance,
dropping in a more advanced date editor (such as a calendar) to replace the
default text-field version, or allowing for "object" fields where you can
paste or create generic objects etc.  If I do this work (at least the basic
mechanisms, if not the ideal ones), would Digital Creations be willing to
incorporate the changes? I am currently developing on 2.1.4, but can upgrade
if there have been any changes in this area. If not, are there any
suggestions on other means to accomplish the same ends (complex property
data types)?

Here is the example of creating the converters:
	A product wishing to use these converters merely imports this
module, and is then able to use property types such as VRML97_SFVec3f (a
single-field vector composed of three-floats).  Currently, they will have to
also create custom property management pages as well :( .

Enjoy yourselves,
Mike

8<____ vrmltypeconverters.py _________
from ZPublisher import Converters
import re, string
whiteSpaceRegex = re.compile( '[ \011-\015,]+' )
killBrackets = string.maketrans( '[]()','    ')
class field2Vec:
	def __init__ (self, multiple= 0, number= 3, range= ( None, None),
name= "SFVec3f", converter=string.atof):
		self.multiple = multiple
		self.number = number
		self.range = range
		self.name = name
		self.converter = converter
		
	def __call__(self,value):
		''' Convert an HTML field value into a three-element list
'''
		if hasattr (value, "read"):
			value = value.read()
		else:
			value = str( value)
		if not value and not self.multiple:
			raise ValueError ("%s value cannot be
null"%self.name)
		elif not value:
			return []
		# in case someone has used brackets, eliminate them from the
string as white space
		value = string.translate( value, killBrackets)
		value = whiteSpaceRegex.split (value)
		if self.multiple and len(value) % self.number:
			raise ValueError ("%s value must have even multiple
of %s entries, has %s: %s"%( self.name, self.number, len(value), value ) )
		elif (not self.multiple) and len(value) != self.number:
			raise ValueError ("%s value must have %s entries,
has %s: %s"%( self.name, self.number, len(value), value ) )
		# we have a correct number of elements
		result = []
		for item in value:
			try:
				# first see if the value is valid for this
type
				item = self.converter (item)
			except ValueError:
				raise ValueError ("%s value (%s) is not
recognizable as a %s value"%(self.name, item, self.name))
			# now check ranges
			if (self.range [0] is not None) and item <
self.range[0]:
				raise ValueError ("%s value (%s) is below
range for %s elements, minimum is %s"%(self.name, item, self.name,
self.range [0]))
			elif (self.range [1] is not None) and item >
self.range[1]:
				raise ValueError ("%s value (%s) is above
range for %s elements, maximum is %s"%(self.name, item, self.name,
self.range [1]))
			else:
				# okay, we can append
				result.append( item )
		return result

def toInteger (value):
	return string.atoi( value, 0)

Converters.type_converters.update( {
	'VRML97_SFVec3f': field2Vec(),
	'VRML97_SFVec2f': field2Vec( number = 2),
	"VRML97_SFColor": field2Vec( range = (0.0, 1.0) ),
	"VRML97_SFRotation": field2Vec( number = 4),
	"VRML97_SFImage": field2Vec( number = 1, converter =toInteger,
multiple = 1),
	
	"VRML97_MFVec3f":field2Vec( multiple = 1),
	'VRML97_MFVec2f': field2Vec( number = 2, multiple = 1),
	"VRML97_MFColor": field2Vec( range = (0.0, 1.0), multiple = 1 ),
	"VRML97_MFRotation": field2Vec( number = 4, multiple = 1),
	"VRML97_MFInt32": field2Vec( number = 1, converter =toInteger,
multiple = 1 ),
	"VRML97_MFFloat": field2Vec( number = 1, multiple = 1),
})


__________________________________
 Mike C. Fletcher
 Designer, VR Plumber
 http://members.home.com/mcfletch