How to provide a custom Plomino field type as a plugin
======================================================

Plomino provides a set of field types (text, number, richtext, datagrid, etc.).

But a custom Plomino field type can be declared to Plomino from a custom 
package in order to extend the Plomino behavior.

Example:
    >>> from zope.formlib import form
    >>> from zope.interface import implements
    >>> from zope import component
    >>> from zope.pagetemplate.pagetemplatefile import PageTemplateFile
    >>> 
    >>> from zope.schema import getFields
    >>> from zope.schema import Text, TextLine
    >>> 
    >>> try:
    >>>     from five.formlib.formbase import EditForm
    >>> except:
    >>>     #PLONE 3
    >>>     from Products.Five.formlib.formbase import EditForm
    >>> 
    >>> from Products.CMFPlomino.interfaces import IPlominoField
    >>> from Products.CMFPlomino.fields.dictionaryproperty import DictionaryProperty
    >>> 
    >>> from Products.CMFPlomino.fields.base import IBaseField, BaseField

A Zope schema defines the field setting parameters.

    >>> class IRomanNumberField(IBaseField):
    >>>     """
    >>>     Roman number field schema
    >>>     """
    >>>     color = TextLine(title=u'Color',
    >>>                 description=u'Font color to apply to roman number display.',
    >>>                 required=False)
    >>>         

A class derivated from BaseField will implement this interface.
It must mandatorily contain:
- plomino_field_parameters: it declares the field main parameters
- read_template: the PageTemplate in charge of rendering the field in read mode
- edit_template: the PageTemplate in charge of rendering the field in edit mode

It can also overwrite the different methods of BaseField, like processInput (in
charge of converting the submitted value into the actual item value, or 
validate (in charge of validating the submitted value before saving).

    >>> class RomanNumberField(BaseField):
    >>>     """ This field stores integers as roman numerals
    >>>     """
    >>>     implements(IRomanNumberField)
    >>>     
    >>>     plomino_field_parameters = {'interface': IRomanNumberField,
    >>>                                 'label': "RomanNumber",
    >>>                                 'index_type': "FieldIndex"}
    >>>     
    >>>     read_template = PageTemplateFile('roman_read.pt')
    >>>     edit_template = PageTemplateFile('roman_edit.pt')
    >>>     
    >>>    def validate(self, strValue):
    >>>         """
    >>>         """
    >>>         errors=[]
    >>>         fieldname = self.context.id
    >>>         try:
    >>>             v = int(submittedValue)
    >>>         except:
    >>>             errors.append(fieldname + " must be an integer.")
    >>>         return errors
    >>>     
    >>>     def processInput(self, strValue):
    >>>         """ convert int to roman (example based on vegaseat code snippet)
    >>>         """
    >>>         number = int(strValue)
    >>>         numerals = { 1 : "I", 4 : "IV", 5 : "V", 9 : "IX", 10 : "X", 40 : "XL", 
    >>>                      50 : "L", 90 : "XC", 100 : "C", 400 : "CD", 500 : "D", 900 : "CM", 1000 : "M" }
    >>>         result = ""
    >>>         for value, numeral in sorted(numerals.items(), reverse=True):
    >>>             while number >= value:
    >>>                 result += numeral
    >>>                 number -= value
    >>>         return result

The plugin field must be provided as an utility so Plomino can find it
(the utility name must be in upper case):
    >>> component.provideUtility(RomanNumberField, IPlominoField, 'ROMANNUMBER')

And the SettingForm must built based on the field's schema: (no customization needed here)
    >>> for f in getFields(IRomanNumberField).values():
    >>>     setattr(RomanNumberField, f.getName(), DictionaryProperty(f, 'parameters'))
    >>> 
    >>> class SettingForm(EditForm):
    >>>     """
    >>>     """
    >>>     form_fields = form.Fields(IRomanNumberField)
    >>>     

Then in configure.zcml, declare the field as adapter for PlominoField:
(assuming that previous code is in romannumber.py)
   <include package="Products.CMFPlomino.fields"/>
   <adapter
        for="Products.CMFPlomino.interfaces.IPlominoField"
        provides=".romannumber.IRomanNumberField"
        factory=".romannumber.RomanNumberField"
        />

and declare the settings form as a browser page (its name must be xxx+'settings'
where xxx is the utility name in lowercase)
   <browser:page
        name="romannumbersettings"
        for="Products.CMFPlomino.interfaces.IPlominoField"
        class=".romannumber.SettingForm"
        permission="plomino.DESIGN_PERMISSION"
        />

The 2 page templates can be based on the following examples:
roman_read.pt:
    <tal:block tal:define="v options/fieldvalue" tal:content="python:str(v)">XXII</tal:block>

roman_edit.pt:
    <span>
        <input type="text" tal:attributes="name options/fieldname; value options/fieldvalue" />
    </span>
