views.py :  » Database » PyDO » skunkweb-3.4.4 » pylibs » formlib » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Database » PyDO 
PyDO » skunkweb 3.4.4 » pylibs » formlib » views.py
######################################################################## 
#  Copyright (C) 2002 Jacob Smullyan <smulloni@smullyan.org>
#                     Drew Csillag <drew_csillag@yahoo.com>
#  
#      You may distribute under the terms of either the GNU General
#      Public License or the SkunkWeb License, as specified in the
#      README file.
#
########################################################################
#      Credits: many contributions here from James Richards (especially
#      layout code and composite fields).
########################################################################

from containers import FieldContainer
from form import Field,DomainField,Form,FormErrorMessage,\
     _getname, CompositeField, _defaultValueComposer, \
     FieldProxy
from containers import Set
import ecs
from DT.DTUtil import htmlquote

# some base classes.

class Viewable(object):
    def __init__(self, **view_attrs):
        if view_attrs.has_key('value'):
            # setting value as a view attribute is
            # not correct as the value of a field is
            # based initially upon the default value
            raise ValueError, "value is not a settable view attribute"
        self.view_attrs=view_attrs

    def getView(self):
        raise NotImplementedError

class _requirable(object):
    def validate(self, form=None):
        if self.required and self.value in (None, [], ''):
            d={'name' : self.name,
               'description' : self.description}
            try:
                msg=self.required % d
            except TypeError:
                msg="%(description)s is required but has no value" % d
            return [FormErrorMessage(self, msg)]

class ViewableField(_requirable, Field, Viewable):
    def __init__(self,
                 name,
                 description=None,
                 default=None,
                 required=0,
                 multiple=0,
                 setable=1,
                 **view_attrs):
        self.required = required
        Field.__init__(self, name, description, default, multiple, setable)
        Viewable.__init__(self, **view_attrs)

class ViewableDomainField(_requirable, DomainField, Viewable):
    def __init__(self,
                 name,
                 domain,
                 description=None,
                 default=None,
                 required=0,
                 multiple=0,
                 setable=1,
                 lenient=0,
                 **view_attrs):
        self.required = required
        DomainField.__init__(self,
                             name,
                             domain,
                             description,
                             default,
                             multiple,
                             setable,
                             lenient)
        Viewable.__init__(self, **view_attrs)


class InputField(ViewableField):
    type=None

    def __init__(self,
                 name,
                 description=None,
                 default=None,
                 required=0,
                 setable=1,
                 **view_attrs):
        ViewableField.__init__(self,
                               name,
                               description,
                               default,
                               required,
                               multiple=0,
                               setable=setable,
                               **view_attrs)

    def getView(self):
        elem=ecs.Input({'type' : self.type})
        if self.name is not None:
            elem.setAttribute('name', self.name)
        if self.value is not None:
            elem.setAttribute('value', htmlquote(str(self.value)))
        elem.attributes.update(self.view_attrs)
        return elem


########################################################################
# concrete classes.
########################################################################
# First, the one-widget fields.
########################################################################

class PasswordField(InputField):
    type="password"

class TextField(InputField):
    type="text"

class ButtonInputField(InputField):
    type="button"

class FileField(InputField):
    type="file"
    def __init__(self,
                 name,
                 description=None,
                 default=None,
                 required=0,
                 setable=1,
                 store_contents=0,
                 **view_attrs):
        self.store_contents=store_contents        
        InputField.__init__(self,
                            name,
                            description,
                            default,
                            required,
                            setable,
                            **view_attrs)

        
    def _set_value(self, val):
        try:
            v=val.filename
        except AttributeError:
            v=val
        InputField._set_value(self, v)
        if self.store_contents:
            try:
                self.contents=val.contents
            except AttributeError:
                self.contents=None

    value=property(InputField._get_value, _set_value)
    
    def clearValue(self):
        if self.store_contents:
            self.contents=None
        InputField.clearValue(self)
        

        

class HiddenField(InputField):
    type="hidden"
    def __init__(self,
                 name,
                 description=None,
                 default=None,
                 setable=0,
                 **view_attrs):
        InputField.__init__(self,
                            name,
                            description,
                            default,
                            setable=setable,
                            **view_attrs)
    
class SubmitField(InputField):
    type="submit"
    def __init__(self,
                 name=None,
                 description=None,
                 default=None,
                 setable=0,
                 **view_attrs):
        InputField.__init__(self,
                            name,
                            description,
                            default,
                            setable=setable,
                            **view_attrs)

class ImageField(InputField):
    type="image"

class ButtonField(ViewableField):
    def __init__(self,
                 content,
                 name=None,
                 description=None,
                 default=None,
                 multiple=0,
                 **view_attrs):
        ViewableField.__init__(self,
                               name,
                               description,
                               default,
                               multiple,
                               **view_attrs)
        self.content=content
        
    def getView(self):
        elem=ecs.Button()
        if self.name!=None:
            elem.setAttribute('name', self.name)
        if self.value is not None:
            elem.setAttribute('value', htmlquote(str(self.value)))
        if isinstance(self.content, list) or isinstance(self.content, tuple):
            for c in self.content:
                elem.addElement(c)
        else:
            elem.addElement(self.content)
        elem.attributes.update(self.view_attrs)
        return elem
        

class TextAreaField(ViewableField):
    def __init__(self,
                 name,
                 description=None,
                 default=None,
                 required=0,
                 **view_attrs):
        ViewableField.__init__(self,
                               name,
                               description,
                               default,
                               required,
                               multiple=0,
                               **view_attrs)
        
        
    def getView(self):
        elem=ecs.Textarea()
        if self.name is not None:
            elem.setAttribute('name', self.name)
        if self.value is not None:
            elem.addElement(htmlquote(str(self.value)))
        elem.attributes.update(self.view_attrs)
        return elem

########################################################################
# now the domain fields.
########################################################################

class SelectField(ViewableDomainField):
    """\
    A component view which accepts a list of options for composing a <select>
    field:
    - a list of strings ['1','2', '3'] becomes
      <select>
       <option value="1">1</option>
       <option value="2">2</option>
       <option value="3">3</option>
      </select>

    - a list of two element string tuples
      [('One', '1'), ('Two', '2')] becomes
      <select>
        <option value="1">One</option>
        <option value="2">Two</option>
      </select>

    - a list of tuples, each  containing a string key and a subgroup
      list ['My Subgroup', ['1', '2']]:
      <select>
       <optgroup label="My Subgroup">
        <option value="1">1</option>
        <option value="2">2</option>
       </optgroup>
      </select>

    Various combinations of the above basic listing schemes are possible 
    """
    def __init__(self,
                 name,
                 options,
                 description=None,
                 default=None,
                 multiple=0,
                 group_levels=1,
                 **view_attrs):
        self.options, domain=self._parse_options(options,
                                                 max(0, group_levels))
        ViewableDomainField.__init__(self,
                                     name=name,
                                     domain=domain,
                                     description=description,
                                     default=default,
                                     multiple=multiple,
                                     **view_attrs)
        
    def _parse_options(self, options, permit_group=1):
        """
         the options could be:
         - a sequence in which the elements are:
           - SelectOptions;
           - SelectOptionGroups;
           - strings (translated into SelectOptions);
           - 2-tuples (string/string pairs -- also translated
                       into SelectOptions);
           - 2-tuples (string/sequence pairs, with the sequence
                       having the same admissible members as the
                       top-level sequence, with the exception
                       that string/sequence pairs are not permitted
                       to be further nested (by default).  These are
                       translated into SelectOptionGroups).
         - a dict which returns from items() something that meets
           the above criteria.

         If you do want to nest option groups, set group_levels to
         some larger number.  sys.maxint should do it.  If you don't want
         to permit any option groups, set group_levels to zero, or, even
         better, don't try to create any. :)

         """
        optlist=[]
        d=Set()
        if isinstance(options, dict):
            options=options.items()
        for o in [self._coerce_option(x, permit_group) for x in options]:
            d.extend(o.getDomain())
            optlist.append(o)
        return optlist, d

    def _coerce_option(self, option, permit_group=1):
        if isinstance(option, SelectOption):
            return option
        elif isinstance(option, SelectOptionGroup):
            if permit_group:
                return option
            else:
                raise ValueError, "option group not permitted: %s" % option
        elif isinstance(option, str):
            return SelectOption(option)
        elif isinstance(option, tuple):
            if len(option)!=2:
                raise ValueError, "could not parse option: %s" % str(option)
            otext, oval=option
            if isinstance(oval, str):
                return SelectOption(otext, oval)
            else:
                # we should have some sort of container
                # involving an option group.
                if not permit_group:
                    raise ValueError, \
                          "option group not permitted: %s" % str(oval)
                # decrement permit_group 
                subopts, subdom=self._parse_options(oval, permit_group-1)
                return SelectOptionGroup(otext, subopts)
        else:
            raise ValueError, "option could not be coerced: %s" % str(option)

    def _update_select_state(self, option):
        # this is supposed to make the option
        # selected depending on the value of the field.
        # we have to deal with option groups.
        if isinstance(option, SelectOptionGroup):
            for o in option.options:
                self._update_select_state(o)
        else:
            v=self.value
            if v is not None:
                if self.multiple:
                    option.selected=option.name in v
                else:
                    option.selected=option.name==v
        
    def getView(self):
       elem=ecs.Select()
       if self.name:
           elem.setAttribute('name', self.name)
       if self.multiple:
           elem.setAttribute('multiple', 'multiple')
       elem.attributes.update(self.view_attrs)
       for o in self.options:
           self._update_select_state(o)
           elem.addElement(o.getView())
       return elem        

########################################################################
# helper classes for SelectField
########################################################################
class SelectOption(Viewable):
    def __init__(self,
                 description,
                 name=None,
                 selected=None,
                 label=None,
                 **view_attrs):
        self.description=description
        if name is not None:
            self.name=name
        else:
            self.name=description
        self.selected=selected
        self.label=label
        Viewable.__init__(self, **view_attrs)
        
    def getView(self):
        elem=ecs.Option()
        elem.addElement(self.description)
        if self.selected:
            elem.setAttribute('selected', 'selected')
        if self.label is not None:
            elem.setAttribute('label', self.label)
        elem.setAttribute('value', htmlquote(str(self.name)))
        elem.attributes.update(self.view_attrs)
        return elem

    def getDomain(self):
        return [self.name]

class SelectOptionGroup(Viewable):
    def __init__(self, label, options=None, **view_attrs):
        Viewable.__init__(self, **view_attrs)
        self.label=label
        if options:
            self.options=options
        else:
            self.options=[]

    def getView(self):
        elem=ecs.Optgroup()
        elem.setAttribute('label', self.label)
        elem.attributes.update(self.view_attrs)
        for o in self.options:
            elem.addElement(o.getView())
        return elem

    def getDomain(self):
        d=Set()
        for o in self.options:
            d.extend(o.getDomain())
        return d

########################################################################
# radio button and checkbox groups
########################################################################

class ButtonGroupField(ViewableDomainField):
    def __init__(self,
                 name,
                 options,
                 description=None,
                 default=None,
                 multiple=0,
                 type=None,
                 **view_attrs):
        self.options, domain=self._parse_options(options, name, multiple, type)
        ViewableDomainField.__init__(self,
                                     name=name,
                                     domain=domain,
                                     description=description,
                                     default=default,
                                     multiple=multiple,
                                     **view_attrs)
        
        
    def _parse_options(self, options, name, multiple, type):
        d=Set()
        optlist=[]
        if isinstance(options, dict):
            options=options.items()
        for o in [self._coerce_option(x, name, multiple, type) for x in options]:
            d.append(o.value)
            optlist.append(o)
        return optlist, d

    def _coerce_option(self, option, name, multiple, type):
        if isinstance(option, ButtonOption):
            return option
        if type==None:
            type=multiple and 'checkbox' or 'radio'
        if isinstance(option, str):
            return ButtonOption(name=name,
                                value=option,
                                description=option,
                                inputType=type)
        elif isinstance(option, tuple) and len(option)==2:
            return ButtonOption(name=name,
                                value=option[0],
                                description=option[1],
                                inputType=type)
        raise ValueError, "could not parse option: %s" % option

    def _update_checked_state(self, option):
        if self.value is None:
            option.checked=None
        elif self.multiple:
            option.checked=option.value in self.value
        else:
            option.checked=option.value==self.value

    def getView(self):
        # this is a little more speculative than for a select,
        # since it consists of multiple elements. Override this
        # at will; it is meant to be visually adequate but no more.
        table=ecs.Table()
        for o in self.options:
            self._update_checked_state(o)
            tr=ecs.Tr().addElement(ecs.Td(o.description))
            tr.addElement(ecs.Td().addElement(o.getView()))
            table.addElement(tr)
        table.attributes.update(self.view_attrs)
        return table

class SubmitButtonGroupField(ButtonGroupField):
    def __init__(self,
                 name,
                 options,
                 **view_attrs):
        ButtonGroupField.__init__(self,
                                  name,
                                  options,
                                  description=None,
                                  default=None,
                                  multiple=0,
                                  type='submit',
                                  **view_attrs)
    def getView(self):
        table=ecs.Table()
        tr=ecs.Tr()
        for o in self.options:
            tr.addElement(ecs.Td(o.getView()))
        table.addElement(tr)
        table.attributes.update(self.view_attrs)
        return table


class ButtonBar(ViewableDomainField):
    def __init__(self,
                 name,
                 options,
                 setable=1,
                 lenient=0,
                 **view_attrs):
        self.options, domain=self._parse_options(options)
        ViewableDomainField.__init__(self,
                                     name,
                                     domain,
                                     setable=setable,
                                     lenient=lenient,
                                     **view_attrs)

    def _parse_options(self, options):
        d=Set()
        optlist=[]
        for o in options:
            if isinstance(o, tuple):
                d.append(o[0])
                optlist.append(o)
            else:
                d.append(o)
                optlist.append((o, o))
        return optlist, d

    def getView(self):
        tr=ecs.Tr()
        for val, label in self.options:
            b=ecs.Button(label, attributes={'name' : self.name,
                                            'value': htmlquote(str(val))})
            tr.addElement(ecs.Td(b))
        return ecs.Table(tr)
            
            
        

########################################################################
# helper classes for button groups
########################################################################

class ButtonOption(Viewable):
    def __init__(self,
                 name,                 
                 description,
                 value=None,
                 inputType='radio',
                 checked=None,
                 **view_attrs):
        if inputType not in ('radio', 'checkbox', 'submit', 'button'):
            raise ValueError, "invalid input type: %s" % inputType
        self.inputType=inputType
        self.checked=checked
        self.name=name
        self.description=description
        if value is not None:
            self.value=value
        else:
            self.value=description
        Viewable.__init__(self, **view_attrs)
        
    def getView(self):
        elem=ecs.Input({'type' : self.inputType})
        if self.name is not None:
            elem.setAttribute('name', self.name)
        if self.value is not None:
            elem.setAttribute('value', htmlquote(str(self.value)))
        if self.inputType in ('radio', 'checkbox') and self.checked:
            elem.setAttribute('checked', 'checked')
        elem.attributes.update(self.view_attrs)
        return elem

########################################################################
# The layouts used to provide form views
########################################################################
class Layout(object):
    "Superclass for ViewableForm layouts"
    def handleError(self, form, tr, fld):
        numErrs = 0
        if form.errors:
            msgs=form.errors.get(fld)
            if msgs:
                msg='\n'.join([x.errormsg for x in msgs])
                numErrs = numErrs + 1
                em=ecs.Em(msg).setAttribute('class', 'form_error')
                pr = ecs.Pre(em)
                td=ecs.Td(pr).setAttribute('colspan', '2')
                tr.addElement(td)
        return numErrs    
    


class FlowLayout(Layout):
    "A simple layout which arranges its items in a columnar, single row view"
    def layoutFields(self, form, table=None):
        """\
        Arranges the given form's ViewableField list into a flow layout,
        disregarding any nesting within the field list...
        all items are arranged in a single row following the order of the field
        list from the first index of the list [and the first index of any
        nested list] to the last index:
        
        [1, [2,3], 4, [5,6,7]]

        produces

        <table>
         <tr>
          <td>1.description</td><td>1.getView()</td>
          <td>2.description</td><td>2.getView()</td>
          <td>3.description</td><td>3.getView()</td>
          <td>4.description</td><td>4.getView()</td>
          <td>5.description</td><td>5.getView()</td>
          <td>6.description</td><td>6.getView()</td>
          <td>7.description</td><td>7.getView()</td>
         </tr>
        </table>
        """
        if table is None:
            table=ecs.Table()
        errTr = ecs.Tr()
        numErr = 0
        for fld in form.fields:
            numErr = numErr + self.handleError(form, errTr, fld)
            
        if numErr:
            table.addElement(errTr)

        tr = ecs.Tr()
        for fld in form.fields:
            if not hasattr(fld, "getView"):
                continue
            
            if fld.description:
                desTd = ecs.Td().addElement(fld.description)
                vwTd = ecs.Td().addElement(fld.getView())
                desTd.setAttribute('valign', 'top')
                vwTd.setAttribute('valign', 'top')
                tr.addElement(desTd)
                tr.addElement(vwTd)
            else:
                td=ecs.Td().addElement(fld.getView())
                td.setAttribute('valign', 'top')
                td.setAttribute('colspan', '2')
                tr.addElement(td)
        tr.addElement('\n')
        table.addElement(tr)
        return table


class StackLayout(Layout):
    "A simple layout which arranges its items in a single column of many rows"
    def layoutFields(self, form, table=None):
        """\
        Arranges the given form's ViewableField list into a stack layout,
        disregarding any nesting within the field list...all items are
        arranged in a single column following the order of the field list
        from the first index of the list [and the first index of any nested
        list] to the last index:
        
        [1, [2,3], 4, [5,6,7]]

        produces

        <table>
         <tr><td>1.description</td><td>1.getView()</td></tr>
         <tr><td>2.description</td><td>2.getView()</td></tr>        
         <tr><td>3.description</td><td>3.getView()</td></tr>
         <tr><td>4.description</td><td>4.getView()</td></tr>
         <tr><td>5.description</td><td>5.getView()</td></tr>
         <tr><td>6.description</td><td>6.getView()</td></tr>
         <tr><td>7.description</td><td>7.getView()</td></tr>
        </table>
        """
        if table is None:
            table=ecs.Table()
        for fld in form.fields:
            if not hasattr(fld, "getView"):
                continue

            errTr = ecs.Tr()
            numErr = self.handleError(form, errTr, fld)
            if numErr:
                table.addElement(errTr)
                
            tr = ecs.Tr()
            if fld.description:
                desTd = ecs.Td().addElement(fld.description)
                vwTd = ecs.Td().addElement(fld.getView())
                desTd.setAttribute('valign', 'top')
                vwTd.setAttribute('valign', 'top')
                tr.addElement(desTd)
                tr.addElement(vwTd)
            else:
                td=ecs.Td().addElement(fld.getView())
                td.setAttribute('valign', 'top')
                td.setAttribute('colspan', '2')
                tr.addElement(td)
            tr.addElement('\n')
            table.addElement(tr)
        return table



class NestedListLayout(Layout):
    "A layout which mimics the structure of a given nested list as a tabular display"
    def layoutFields(self, form, table=None):
        """\
        Arranges the given form's ViewableField list into a tabular display based
        upon the nesting of the given field list...
        column spanning is based upon the maximum depth of the largest nested list:

        [1, [2,3], 4, [5,6,7]]

        produces

        <table>
         <tr>
          <td>1.description</td><td colspan="5">1.getView()</td>
         </tr>
         <tr>
          <td>2.description</td><td>2.getView()</td>
          <td>3.description</td><td colspan="3">3.getView()</td>
         </tr>
         <tr>
          <td>4.description</td><td colspan="5">4.getViews()</td>
         </tr>
         <tr>
          <td>5.description</td><td>5.getView()</td>
          <td>6.description</td><td>6.getView()</td>
          <td>7.description</td><td>7.getView()</td>
         </tr>
        </table>

        where ecs.Table is returned by the method:
        
        1) if a table was passed to the method, the same table is returned with
           the fields laid out inside it
        2) if a table was not passed, the default table is generated and returned
           with the fields laid out 
        """
        if table is None:
            table=ecs.Table()
            
        for tstFnm in form.fieldLayout:
            tr=ecs.Tr() 
            if isinstance(tstFnm, list) or isinstance(tstFnm, tuple):
                self.handleList(form, tstFnm, tr, table)
            else: 
                self.handleField(form, form.fields[tstFnm], tr, table)
            table.addElement(tr)
            table.addElement('\n')
        return table    

    def handleList(self, form, list, tr, table):
        errTr = ecs.Tr()
        ttlErr = 0
        for fnm in list:
            fld = form.fields[fnm]
            # handle the errors display...these will always span two columns
            numErrs = self.handleError(form, errTr, fld)
            if not numErrs:
                # if there were no errors, we need to add an empty TD for
                #this field's error
                errTr.addElement(ecs.Td().setAttribute('colspan', '2')\
                                 .addElement("&nbsp;"))
            else:
                # increment the total number of errors
                ttlErr = ttlErr + numErrs
                                 
        if ttlErr:
            table.addElement(errTr)
        
        # some rows may have less items than the max depth, in which case we should
        # not span the remaining columns or a very ugly GUI is created
        colspan = 0
        lstLen = len(list)
        if lstLen < form.maxDepth:
            # note that there are 2 <td> cells for each item in any row
            colspan = 2 * (form.maxDepth - lstLen)
        
        for idx in range(0, lstLen):
            fnm = list[idx]
            fld = form.fields[fnm]

            if not hasattr(fld, "getView"):
                return
            
            if idx == lstLen - 1:
                # if we are on the last column, add the colspan, else add no
                #colspan
                self.handleField(form, fld, tr, table, colspan, fromList=1)
            else:
                self.handleField(form, fld, tr, table, 0, fromList=1)
                

    def handleField(self, form, f, tr, table, colspan=0, fromList=0):
        if not fromList:
            # if we are not coming from a list [aka handleList()],
            # then this method must check for errors itself
            errTr = ecs.Tr()
            numErr = self.handleError(form, errTr, f)
            if numErr:
                table.addElement(errTr)

        if not hasattr(f, "getView"):
            return 
            
        if f.description:
            desTd = ecs.Td().addElement(f.description)
            vwTd = ecs.Td().addElement(f.getView())
            desTd.setAttribute('valign', 'top')
            vwTd.setAttribute('valign', 'top')
            if colspan:
                vwTd.setAttribute('colspan', colspan)
            tr.addElement(desTd)
            tr.addElement(vwTd)
        else:
            td=ecs.Td().addElement(f.getView())
            td.setAttribute('valign', 'top')
            if colspan:
                td.setAttribute('colspan', colspan)
            else:
                td.setAttribute('colspan', '2')
            tr.addElement(td)
        tr.addElement('\n')
        return 



########################################################################
# the form itself.
########################################################################

class ViewableForm(Viewable, Form):
    def __init__(self,
                 name=None,
                 method=None,
                 action=None,
                 enctype=None,
                 fields=None,
                 validators=None,
                 processors=None,
                 layout=None,
                 **view_attrs):
        
        Form.__init__(self,
                      name,
                      method,
                      action,
                      enctype,
                      fields,
                      validators,
                      processors)
        Viewable.__init__(self, **view_attrs)
        self.layout=layout or StackLayout()

    def _get_fields(self):
        return self._fields

    def _set_fields(self, fields):
        flatfields, self._fieldLayout, self.maxDepth = self._flattenFields(fields)
        Form._set_fields(self, flatfields)

    fields=property(_get_fields, _set_fields)

    def _get_fieldLayout(self):
        return self._fieldLayout

    def _set_fieldLayout(self, newLayout):
        """\
        Means for manipulating the layout of the fields of a form
        without reinitializing the set of fields.  Expects a possibly
        nested list of field name against which the current layout
        object will construct a view.
        """
        self._fieldLayout=newLayout

    fieldLayout=property(_get_fieldLayout, _set_fieldLayout)     


    def _flattenFields(self, fields):
        """\
        Ensures that the given list of fields is flattened into a
        one-dimensional list as required by Form superclass also
        flattens the fields used for generating a layout into a
        listing of field names which mimics any nesting in the
        original, unflattened field list

        returns

        (flatfields, layoutfields, maxDepth)
        """
        maxDepth = 1 # the longest sublist of fields
        flds = []
        layout = []
        for tstfld in fields:
            if isinstance(tstfld, list) or isinstance(tstfld, tuple):
                sublst = []
                if len(tstfld) > maxDepth:
                    maxDepth = len(tstfld)
                for subfld in tstfld:
                    flds.append(subfld)
                    sublst.append(subfld.name)
                layout.append(sublst)    
            else:         
                flds.append(tstfld)
                layout.append(tstfld.name)
        return (flds, layout, maxDepth)
    

    def getView(self):
        elem=ecs.Form()
        if self.method:
            elem.setAttribute('method', self.method)
        if self.enctype:
            elem.setAttribute('enctype', self.enctype)
        if self.action:
            elem.setAttribute('action', self.action)
        elem.attributes.update(self.view_attrs)
        if self.name:
            elem.setAttribute('name', self.name)
        table=ecs.Table()
        table.addElement('\n')
        top_level_errors=self.errors.get(self)
        if top_level_errors:
            top_level_error='<br />'.join([x.errormsg for x \
                                           in top_level_errors])
            em=ecs.Em(top_level_error).setAttribute('class',
                                                    'form_error')
            tr=ecs.Tr().addElement(ecs.Td(em)\
                                   .setAttribute('colspan',
                                                 str(2 * self.maxDepth)))
            table.addElement(tr)
            table.addElement('\n')

        self.layout.layoutFields(self, table)    
        elem.addElement('\n')
        elem.addElement(table)
        elem.addElement('\n')
        return elem


########################################################################
# viewable version of the composite field
########################################################################

class ViewableFieldProxy(FieldProxy, Viewable):
    "A viewable version of the FieldProxy which overrides"\
    "the view produced to use the proxied name for "\
    "submissions instead of the name of the proxied field."

    def __init__(self, proxyName, proxiedField):
        FieldProxy.__init__(self, proxyName, proxiedField)

    def getView(self):
        tmpVw = self.field.getView()
        tmpVw.setAttribute('name', self.name)
        return tmpVw

class ViewableCompositeField(Viewable, CompositeField):
    def __init__(self,
                 name,
                 description,
                 default=None,
                 multiple=1,
                 setable=1,
                 componentFields=None,
                 componentFieldDelimiter='_',
                 valueComposer=_defaultValueComposer,
                 layout=None):
        CompositeField.__init__(self,
                                name,
                                description,
                                default,
                                multiple,
                                setable,
                                componentFields,
                                componentFieldDelimiter,
                                valueComposer)

        # must override initialization of composite fields to ensure that ViewableFieldProxies 
        # are used
        tmpComponents = []
        for fld in componentFields:
            prxy = ViewableFieldProxy(self._getComponentName(fld), fld)
            tmpComponents.append(prxy)
        self._fields = FieldContainer(tmpComponents,
                                          fieldmapper=_getname,
                                          storelists=0)

        self.layout=layout or StackLayout()

    def getView(self):
        return self.layout.layoutFields(self)

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.