[Zope-dev] Adding your own (complex) data types to property p ages: example and problems...

Mike Fletcher mfletch@tpresence.com
Thu, 4 May 2000 17:08:47 -0400


This message is in MIME format. Since your mail reader does not understand
this format, some or all of this message may not be legible.

------_=_NextPart_000_01BFB60C.F4E4D144
Content-Type: text/plain;
	charset="iso-8859-1"

Incidentally, I just finished the simplistic method I described.  (Attached
2 files, import the .py file and it updates PropertyPages to use its
mechanisms).  I've only tested it lightly (1 or 2 properties per input), but
it is pretty much a direct rip of the stuff in properties.py .

If general consensus is that this is too ugly, I'll stop working on it (I
was thinking of putting this and the extant converters module into one
registry class/object that would have registration/deregistration support,
but what's here now does what I need it to do (incidentally, it also adds
all of the types with input handlers to the list of datatypes in the "create
property" part of the properties form).

"While we're waiting for the real solutions, this might fix the problem."
Enjoy,
Mike


------_=_NextPart_000_01BFB60C.F4E4D144
Content-Type: application/octet-stream;
	name="propertyinput.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="propertyinput.py"

from DocumentTemplate.DT_Util import html_quote
from Globals import HTMLFile=20
from OFS import PropertySheets
import string
def getPropertyInputHTML( self, propertyMapping):
	''' Retrieve the appropriate HTML input field for this datatype '''
	ID =3D propertyMapping["id"]
	if self.hasProperty (ID):
		value =3D self.getProperty (ID)
		# input converters is a global mapping...
		converter =3D inputConverters.get ( propertyMapping.get ("type", =
"string"), "string" )
		return converter (propertyMapping, value, self)
	elif propertyMapping.has_key ("default"):
		converter =3D inputConverters.get ( propertyMapping.get ("type", =
"string"), "string" )
		return converter (propertyMapping, propertyMapping["default"], self)
	else:
		return ""
def getPropertyTypes( self ):
	'''Retrieve the names of all known property types'''
	keys =3D inputConverters.keys()
	keys.sort()
	return keys
PropertySheets.PropertySheet.getPropertyInputHTML =3D =
getPropertyInputHTML
PropertySheets.PropertySheet.getPropertyTypes =3D getPropertyTypes
PropertySheets.PropertySheet.manage =3D HTMLFile( "properties", =
globals())

def RepresentationInput ( mapping, value, sheet):
	''' Create HTML input field for integer/float value '''
	template =3D '''<input type=3D"text" name=3D"%(id)s:%(type)s" =
size=3D"35" value=3D"%(value)s">'''
	value =3D html_quote(repr( value))
	id =3D mapping.get ("id")
	type =3D mapping.get ("type")
	return template%locals ()
def LongInput(mapping, value, sheet):
	''' Create HTML input field for integer/float value '''
	template =3D '''<input type=3D"text" name=3D"%(id)s:%(type)s" =
size=3D"35" value=3D"%(value)s">'''
	value =3D repr( value )
	if value and value[-1] in ('l',"L"):
		value =3D value[:-1]
	value =3D html_quote( value )
	id =3D mapping.get ("id")
	type =3D mapping.get ("type")
	return template%locals ()
def StringInput (mapping, value, sheet):
	''' Create HTML input field for string value'''
	template =3D '''<input type=3D"text" name=3D"%(id)s:%(type)s" =
size=3D"35" value=3D"%(value)s">'''
	value =3D html_quote(str( value))
	id =3D mapping.get ("id")
	type =3D mapping.get ("type")
	return template%locals ()
StandardDateInput =3D StringInput

def BooleanInput (mapping, value, sheet):
	''' Create HTML boolean input field '''
	template =3D '''<input type=3D"checkbox" name=3D"%(id)s:%(type)s" =
size=3D"35" %(checked)s>'''
	id =3D mapping.get ("id")
	type =3D mapping.get ("type")
	if value:
		checked =3D "CHECKED"
	else:
		checked =3D ""
	return template% locals ()

def TokenInput (mapping, value, sheet):
	''' Create HTML token input field '''
	template =3D '''<input type=3D"text" name=3D"%(id)s:%(type)s" =
size=3D"35" value=3D"%(values)s">'''
	id =3D mapping.get ("id")
	type =3D mapping.get ("type")
	values =3D string.join ( map (html_quote, map( str, value)), " " )
	return template% locals ()

def TextInput (mapping, value, sheet):
	'''Create an HTML text input field (i.e. multiple lines of text) '''
	template =3D '''<textarea name=3D"%(id)s:%(type)s" rows=3D"6" =
cols=3D"35">%(value)s</textarea>'''
	id =3D mapping.get ("id")
	type =3D mapping.get ("type")
	value =3D html_quote(value)
	return template% locals ()

def LinesInput(mapping, value, sheet):
	''' Creating HTML lines input field (i.e. lines of separated text =
strings) '''
	template =3D '''<textarea name=3D"%(id)s:%(type)s" rows=3D"6" =
cols=3D"35">%(value)s</textarea>'''
	id =3D mapping.get ("id")
	type =3D mapping.get ("type")
	value =3D string.join ( map (html_quote, map( str, value)), "\n" )
	return template% locals ()

def resolveAttribute(object, attribute):
	variable =3D string.split (attribute, ".")
	while variable:
		try:
			object =3D object.getProperty( variable[0])
		except (AttributeError, KeyError):
			try:
				object =3D getattr (object, variable [0])
			except (AttributeError, KeyError):
				try:
					object =3D object [variable [0]]
				except (AttributeError, KeyError, TypeError), value:
					raise AttributeError("Object %s does not have attribute %s, =
(failed to resolve %s)"% (object, attribute, value))
		del variable[0]
	return object
def SelectionInput( mapping, value, sheet):
	''' Create an HTML input for a selection property '''
	if mapping.has_key("select_variable"):
		id =3D mapping ["id"]
		type =3D mapping ["type"]
		bigTemplate =3D '''<select =
name=3D"%(id)s:%(type)s">%(options)s</select>'''
		selectionList =3D resolveAttribute( sheet, mapping =
["select_variable"])
		if callable(selectionList):
			selectionList =3D selectionList()
		optionTemplate =3D '''<option %(selected)s>%(item)s</option>'''
		optionList =3D []
		for item in selectionList:
			if item =3D=3D value:
				selected =3D "SELECTED"
			else:
				selected =3D ""
			item =3D html_quote(str(item))
			optionList.append (optionTemplate% locals ())
		options =3D string.join ( optionList,'\n')
		return bigTemplate%locals()
	else:
		return '''No source attribute specified for selection property'''
def MultipleSelectionInput (mapping, value, sheet):
	''' Create an HTML input for a multiple selection property '''
	if mapping.has_key("select_variable"):
		id =3D mapping ["id"]
		type =3D "list" # note: this is not the type specified, this is not =
likely a good idea
		bigTemplate =3D '''<select name=3D"%(id)s:%(type)s" size=3D"%(size)s" =
MULTIPLE>%(options)s</select>'''
		selectionList =3D resolveAttribute( sheet, mapping =
["select_variable"])
		if callable(selectionList):
			selectionList =3D selectionList()
		optionTemplate =3D '''<option %(selected)s>%(item)s</option>'''
		optionList =3D []
		for item in selectionList:
			if item in value:
				selected =3D "SELECTED"
			else:
				selected =3D ""
			item =3D html_quote(str(item))
			optionList.append (optionTemplate% locals ())
		size =3D min( 7, len(optionList))
		options =3D string.join ( optionList,'\n')
		return bigTemplate%locals()
	else:
		return '''No source attribute specified for multiple selection =
property'''


inputConverters =3D {
	"string": StringInput,
	"long": LongInput,
	"int": RepresentationInput,
	"float": RepresentationInput,
	"date": StandardDateInput,
	"datetime": StandardDateInput,
	"boolean": BooleanInput,
	"tokens": TokenInput,
	"text": TextInput,
	"lines": LinesInput,
	"selection": SelectionInput,
	"multiple selection": MultipleSelectionInput,
}

------_=_NextPart_000_01BFB60C.F4E4D144
Content-Type: application/octet-stream;
	name="properties.dtml"
Content-Disposition: attachment;
	filename="properties.dtml"

<dtml-var standard_html_header>
<dtml-var manage_tabs>

<dtml-if Principia-Version>
<p>
<em>You are currently working in version <dtml-var Principia-Version></em>
</p>
</dtml-if Principia-Version>

<P>
Properties allow you to assign simple values to Zope objects.
</P>

<form action="<dtml-var URL1>" method="POST">
<dtml-if propertyMap>
<p>
The following properties are defined for this item. 
<dtml-if property_extensible_schema__>
To <a href="#addpropform">
add a new property</a>, enter a name, type and value for the new property 
and click the &quot;Add&quot; button. 
</dtml-if>
To change property values, edit the 
values and click "Save Changes". 
</p>
<table border="0" cellspacing="0" cellpadding="2">
<dtml-in propertyMap mapping>
<tr>
  <td align="left" valign="top" width="16">
  <dtml-if "'d' in _['sequence-item'].get('mode', 'awd')">
  <input type="checkbox" name="ids:list" value="<dtml-var id html_quote>" ID="cb-<dtml-var id>">
  <dtml-else>
  </dtml-if>
  </td>
  <td align="left" valign="top">
  <strong><LABEL FOR="cb-<dtml-var id>"><dtml-var "propertyLabel(id)"></LABEL></strong>
  </td>
  <td align="left" valign="top">
  <dtml-if "'w' in _['sequence-item'].get('mode', 'awd')">
    <dtml-var "getPropertyInputHTML( _['sequence-item'] )">
  <dtml-else>
  <table border="1">
  <tr><td><dtml-var "getProperty(id)" html_quote></td></tr>
  </table>
  </dtml-if>
  </td>
</tr>
</dtml-in>
<tr>
  <td align="left" valign="top" width="16">
  </td>
  <td align="left" valign="top" width="16">
  </td>
  <td align="left" valign="top">
  <input type="submit" name="manage_editProperties:method" 
   value="Save Changes">
  <input type="submit" name="manage_delProperties:method" value="Delete">
  </td>
</tr>
</table>

<dtml-else>
<p>
There are currently no properties defined for this item. 
<dtml-if property_extensible_schema__>
To add a property, click the &quot;Add...&quot; button.
</dtml-if>
</p>

</dtml-if>
</form>

<dtml-if property_extensible_schema__>
<a name="addpropform">
<form action="<dtml-var URL1>/manage_addProperty" method="POST">
<p>
To add a new property, enter a name, type and value for the new 
property and click the &quot;Add&quot; 
button. For &quot;selection&quot; and &quot;multiple selection&quot;
properties enter the name of a selection variable in the &quot;Value&quot;
field. The selection variable is a property or method that returns a list
of strings from which the selection(s) can be chosen.
</p>
<table>
<tr>
  <th align="left" valign="top">Id</th>
  <td align="left" valign="top"><input type="text" name="id" size="20"></td>
  <th align="left" valign="top">Type</th>
  <td align="left" valign="top">
    <select name="type">
      <dtml-in getPropertyTypes>
        <option<dtml-if "_['sequence-item'] == 'string'"> SELECTED</dtml-if>>
          <dtml-var sequence-item></option>
      </dtml-in>
    </select>
  </td>
</tr>
<tr>
  <th align="left" valign="top">Value</th>
  <td colspan=2 align="left" valign="top">
    <input type="text" name="value" size="30">
  </td>
  <td align="right" valign="top">
  <input type="submit" value=" Add ">
  </td>
</tr>
</table>
</form>
</dtml-if>
<dtml-var standard_html_footer>

------_=_NextPart_000_01BFB60C.F4E4D144--