src/pyams_content/shared/form/field.py
changeset 170 26aefef3d0aa
child 372 719c3edee5c1
equal deleted inserted replaced
169:483b0f16e9a6 170:26aefef3d0aa
       
     1 #
       
     2 # Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
       
     3 # All Rights Reserved.
       
     4 #
       
     5 # This software is subject to the provisions of the Zope Public License,
       
     6 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
       
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
       
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
       
    10 # FOR A PARTICULAR PURPOSE.
       
    11 #
       
    12 
       
    13 __docformat__ = 'restructuredtext'
       
    14 
       
    15 
       
    16 # import standard library
       
    17 from collections import OrderedDict
       
    18 
       
    19 # import interfaces
       
    20 from pyams_content.shared.form.interfaces import IFormFieldFactory, IFormField, IFormFieldContainer, \
       
    21     IFormFieldContainerTarget, FORM_FIELD_CONTAINER_KEY
       
    22 from pyams_i18n.interfaces import II18n
       
    23 from zope.annotation.interfaces import IAnnotations
       
    24 from zope.location.interfaces import ISublocations
       
    25 from zope.traversing.interfaces import ITraversable
       
    26 
       
    27 # import packages
       
    28 from persistent import Persistent
       
    29 from pyams_utils.adapter import adapter_config, ContextAdapter
       
    30 from pyams_utils.registry import utility_config
       
    31 from pyams_utils.request import check_request
       
    32 from pyams_utils.schema import MailAddressField
       
    33 from pyams_utils.vocabulary import vocabulary_config
       
    34 from pyramid.threadlocal import get_current_registry
       
    35 from zope.component.globalregistry import getGlobalSiteManager
       
    36 from zope.container.contained import Contained
       
    37 from zope.container.ordered import OrderedContainer
       
    38 from zope.interface import implementer
       
    39 from zope.lifecycleevent import ObjectCreatedEvent
       
    40 from zope.location import locate
       
    41 from zope.schema import TextLine, Text, Bool, Int, Decimal, URI, Date, Choice, List
       
    42 from zope.schema.fieldproperty import FieldProperty
       
    43 from zope.componentvocabulary.vocabulary import UtilityVocabulary, UtilityTerm
       
    44 
       
    45 from pyams_content import _
       
    46 
       
    47 
       
    48 @implementer(IFormField)
       
    49 class FormField(Persistent, Contained):
       
    50     """Form field definition persistent class"""
       
    51 
       
    52     name = FieldProperty(IFormField['name'])
       
    53     field_type = FieldProperty(IFormField['field_type'])
       
    54     label = FieldProperty(IFormField['label'])
       
    55     description = FieldProperty(IFormField['description'])
       
    56     placeholder = FieldProperty(IFormField['placeholder'])
       
    57     values = FieldProperty(IFormField['values'])
       
    58     default = FieldProperty(IFormField['default'])
       
    59     required = FieldProperty(IFormField['required'])
       
    60     visible = FieldProperty(IFormField['visible'])
       
    61 
       
    62 
       
    63 @implementer(IFormFieldContainer)
       
    64 class FormFieldContainer(OrderedContainer):
       
    65     """Form fields container persistent class"""
       
    66 
       
    67     def get_fields(self):
       
    68         registry = getGlobalSiteManager()
       
    69         fields = []
       
    70         for field in self.values():
       
    71             if field.visible:
       
    72                 factory = registry.queryUtility(IFormFieldFactory, name=field.field_type)
       
    73                 if factory is not None:
       
    74                     fields.append(factory.get_schema_field(field))
       
    75         return fields
       
    76 
       
    77 
       
    78 @adapter_config(context=IFormFieldContainerTarget, provides=IFormFieldContainer)
       
    79 def FormFieldContainerFactory(context):
       
    80     """Form fields container factory"""
       
    81     annotations = IAnnotations(context)
       
    82     container = annotations.get(FORM_FIELD_CONTAINER_KEY)
       
    83     if container is None:
       
    84         container = annotations[FORM_FIELD_CONTAINER_KEY] = FormFieldContainer()
       
    85         get_current_registry().notify(ObjectCreatedEvent(container))
       
    86         locate(container, context, '++fields++')
       
    87     return container
       
    88 
       
    89 
       
    90 @adapter_config(name='fields', context=IFormFieldContainerTarget, provides=ITraversable)
       
    91 class FormFieldContainerNamespace(ContextAdapter):
       
    92     """Form fields container ++fields++ namespace"""
       
    93 
       
    94     def traverse(self, name, firtherpath=None):
       
    95         return IFormFieldContainer(self.context)
       
    96 
       
    97 
       
    98 @adapter_config(name='fields', context=IFormFieldContainerTarget, provides=ISublocations)
       
    99 class FormFieldsContainerSublocations(ContextAdapter):
       
   100     """Form fields container sub-locations adapter"""
       
   101 
       
   102     def sublocations(self):
       
   103         return IFormFieldContainer(self.context).values()
       
   104 
       
   105 
       
   106 #
       
   107 # Form fields factories
       
   108 #
       
   109 
       
   110 @vocabulary_config(name='PyAMS form field types')
       
   111 class FormFieldTypesVocabulary(UtilityVocabulary):
       
   112     """Form field types vocabulary"""
       
   113 
       
   114     interface = IFormFieldFactory
       
   115 
       
   116     def __init__(self, context, **kw):
       
   117         request = check_request()
       
   118         registry = request.registry
       
   119         translate = request.localizer.translate
       
   120         utils = [(name, translate(util.label))
       
   121                  for (name, util) in sorted(registry.getUtilitiesFor(self.interface),
       
   122                                             key=lambda x: x[1].weight)]
       
   123         self._terms = OrderedDict((title, UtilityTerm(name, title)) for name, title in utils)
       
   124 
       
   125     def __iter__(self):
       
   126         return iter(self._terms.values())
       
   127 
       
   128 
       
   129 class BaseFormFieldFactory(object):
       
   130     """Base form field factory"""
       
   131 
       
   132     field_factory = None
       
   133 
       
   134     def get_schema_field(self, field):
       
   135         i18n = II18n(field)
       
   136         result = self.field_factory(title=i18n.query_attribute('label'),
       
   137                                     description=i18n.query_attribute('description'),
       
   138                                     required=field.required,
       
   139                                     default=i18n.query_attribute('default'))
       
   140         result.__name__ = field.name
       
   141         return result
       
   142 
       
   143 
       
   144 @utility_config(name='textline', provides=IFormFieldFactory)
       
   145 class TextLineFieldFactory(BaseFormFieldFactory):
       
   146     """Textline field factory"""
       
   147 
       
   148     label = _("Text")
       
   149     weight = 1
       
   150 
       
   151     field_factory = TextLine
       
   152 
       
   153 
       
   154 @utility_config(name='text', provides=IFormFieldFactory)
       
   155 class TextFieldFactory(BaseFormFieldFactory):
       
   156     """Text field factory"""
       
   157 
       
   158     label = _("Multi-lines text")
       
   159     weight = 2
       
   160 
       
   161     field_factory = Text
       
   162 
       
   163 
       
   164 @utility_config(name='bool', provides=IFormFieldFactory)
       
   165 class BooleanFieldFactory(BaseFormFieldFactory):
       
   166     """Boolean field factory"""
       
   167 
       
   168     label = _("Boolean")
       
   169     weight = 3
       
   170 
       
   171     field_factory = Bool
       
   172 
       
   173 
       
   174 @utility_config(name='integer', provides=IFormFieldFactory)
       
   175 class IntegerFieldFactory(BaseFormFieldFactory):
       
   176     """Integer field factory"""
       
   177 
       
   178     label = _("Integer")
       
   179     weight = 4
       
   180 
       
   181     field_factory = Int
       
   182 
       
   183 
       
   184 @utility_config(name='decimal', provides=IFormFieldFactory)
       
   185 class DecimalFieldFactory(BaseFormFieldFactory):
       
   186     """Decimal field factory"""
       
   187 
       
   188     label = _("Decimal")
       
   189     weight = 5
       
   190 
       
   191     field_factory = Decimal
       
   192 
       
   193 
       
   194 @utility_config(name='mail', provides=IFormFieldFactory)
       
   195 class MailFieldFactory(BaseFormFieldFactory):
       
   196     """Mail field factory"""
       
   197 
       
   198     label = _("E-mail address")
       
   199     weight = 10
       
   200 
       
   201     field_factory = MailAddressField
       
   202 
       
   203 
       
   204 @utility_config(name='uri', provides=IFormFieldFactory)
       
   205 class URIFieldFactory(BaseFormFieldFactory):
       
   206     """URI field factory"""
       
   207 
       
   208     label = _("URI")
       
   209     weight = 11
       
   210 
       
   211     field_factory = URI
       
   212 
       
   213 
       
   214 @utility_config(name='date', provides=IFormFieldFactory)
       
   215 class DateFieldFactory(BaseFormFieldFactory):
       
   216     """Date field factory"""
       
   217 
       
   218     label = _("Date")
       
   219     weight = 15
       
   220 
       
   221     field_factory = Date
       
   222 
       
   223 
       
   224 class ValuesFieldFactory(BaseFormFieldFactory):
       
   225     """Values-based field factory"""
       
   226 
       
   227 
       
   228 @utility_config(name='choice', provides=IFormFieldFactory)
       
   229 class ChoiceFieldFactory(ValuesFieldFactory):
       
   230     """Choice field factory"""
       
   231 
       
   232     label = _("Choice")
       
   233     weight = 20
       
   234 
       
   235     field_factory = Choice
       
   236 
       
   237     def get_schema_field(self, field):
       
   238         i18n = II18n(field)
       
   239         result = self.field_factory(title=i18n.query_attribute('label'),
       
   240                                     description=i18n.query_attribute('description'),
       
   241                                     required=field.required,
       
   242                                     default=i18n.query_attribute('default'),
       
   243                                     values=field.values)
       
   244         result.__name__ = field.name
       
   245         return result
       
   246 
       
   247 
       
   248 @utility_config(name='list', provides=IFormFieldFactory)
       
   249 class ListFieldFactory(ValuesFieldFactory):
       
   250     """List field factory"""
       
   251 
       
   252     label = _("List")
       
   253     weight = 51
       
   254 
       
   255     field_factory = List
       
   256 
       
   257     def get_schema_field(self, field):
       
   258         i18n = II18n(field)
       
   259         result = self.field_factory(title=i18n.query_attribute('label'),
       
   260                                     description=i18n.query_attribute('description'),
       
   261                                     required=field.required,
       
   262                                     default=[i18n.query_attribute('default')],
       
   263                                     value_type=Choice(values=field.values))
       
   264         result.__name__ = field.name
       
   265         return result