ProxyField.py 6.76 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2
##############################################################################
#
3
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
#                    Jean-Paul Smets <jp@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

from Products.Formulator import Widget, Validator
from Products.Formulator.Field import ZMIField
from Products.Formulator.DummyField import fields
from Products.Formulator.Errors import ValidationError
from Products.ERP5Type.Utils import convertToUpperCase
from Products.CMFCore.utils import getToolByName

from Products.PageTemplates.PageTemplateFile import PageTemplateFile

from Globals import get_request
from Products.PythonScripts.Utility import allow_class

from Products.PythonScripts.standard import url_quote_plus

43
from AccessControl import ClassSecurityInfo
Jean-Paul Smets's avatar
Jean-Paul Smets committed
44 45
import string

46
from zLOG import LOG, WARNING
47
from Acquisition import aq_base, aq_inner, aq_acquire, aq_chain
Jean-Paul Smets's avatar
Jean-Paul Smets committed
48 49 50 51 52 53 54 55 56

class ProxyWidget(Widget.Widget):
  """
      A widget that renders itself as a field from another form
      after changing its title and id. It is recommended to define
      a master form on which complex fields with a lot of TALES
      are defined in order to minimize code duplication.
  """

57
  property_names = [
58 59 60
    'form_id',
    'field_id',
    'extra_context',
Jean-Paul Smets's avatar
Jean-Paul Smets committed
61 62 63 64 65
  ]

  form_id = fields.StringField(
                                'form_id',
                                title='Form ID',
66 67
                                description= \
                                  "ID of the master form.",
Jean-Paul Smets's avatar
Jean-Paul Smets committed
68 69 70 71 72 73
                                default="",
                                required=1)

  field_id = fields.StringField(
                                'field_id',
                                title='Field ID',
74 75
                                description= \
                                  "ID of the field in the master form.",
Jean-Paul Smets's avatar
Jean-Paul Smets committed
76 77 78
                                default="",
                                required=1)

79 80
  # XXX FIXME This seems against the definition of proxy field...
  # Remove it as soon as possible
81 82 83
  extra_context = fields.ListTextAreaField(
                                'extra_context', 
                                title='Extra Context', 
84
                                description='Additional context variables.',
85 86 87
                                default=(), 
                                required=0)

Jean-Paul Smets's avatar
Jean-Paul Smets committed
88 89
  def render(self, field, key, value, REQUEST):
    """
90
    Render proxy field
Jean-Paul Smets's avatar
Jean-Paul Smets committed
91
    """
92 93 94 95 96 97
    result = ''
    proxy_field = field.getTemplateField()
    if proxy_field is not None:
      REQUEST = field.updateContext(REQUEST)
      result = proxy_field.widget.render(proxy_field, key, value, REQUEST)
    return result
Jean-Paul Smets's avatar
Jean-Paul Smets committed
98 99

  def render_view(self, field, value):
100
    """
Jean-Paul Smets's avatar
Jean-Paul Smets committed
101 102
      Display proxy field
    """
103 104 105 106 107
    result = ''
    proxy_field = field.getTemplateField()
    if proxy_field is not None:
      result = proxy_field.widget.render_view(proxy_field, value)
    return result
Jean-Paul Smets's avatar
Jean-Paul Smets committed
108 109 110 111 112

class ProxyValidator(Validator.Validator):
  """
    Validation of entered value through proxy field
  """
113
  property_names = []
Jean-Paul Smets's avatar
Jean-Paul Smets committed
114 115

  def validate(self, field, key, REQUEST):
116 117
    proxy_field = field.getTemplateField()
    REQUEST = field.updateContext(REQUEST)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
118 119 120 121 122 123 124 125 126 127 128 129
    try:
      result = proxy_field.validator.validate(proxy_field, key, REQUEST)
    except ValidationError, error:
      error.field_id = field.id
      raise error
    return result

ProxyWidgetInstance = ProxyWidget()
ProxyValidatorInstance = ProxyValidator()

class ProxyField(ZMIField):
  meta_type = "ProxyField"
130
  security = ClassSecurityInfo()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
131 132 133

  widget = ProxyWidgetInstance
  validator = ProxyValidatorInstance
134

135 136 137
  def getTemplateField(self):
    """
    Return template field of the proxy field.
138
    """
139 140 141 142 143 144 145 146 147 148 149 150 151
    form = self.aq_parent
    object = form.aq_parent
    try:
      proxy_form = getattr(object, self.get_value('form_id'))
      proxy_field = aq_base(getattr(proxy_form, self.get_value('field_id')))
      proxy_field = proxy_field.__of__(form)
    except AttributeError:
      LOG('ProxyField', WARNING, 
          'Could not get a field from a proxy field %s in %s' % \
              (self.id, object.id))
      proxy_field = None
    return proxy_field

152 153 154 155 156 157 158 159 160 161 162 163
  def render_htmlgrid(self, value=None, REQUEST=None, key=None):
    """
    render_htmlgrid returns a list of tuple (title, html render)
    We will use title generated by the widget.
    """
    result = ()
    proxy_field = self.getTemplateField()
    if proxy_field is not None :
      result = proxy_field.render_htmlgrid(key=key, value=value,
                                           REQUEST=REQUEST)
    return result

164
  def updateContext(self, REQUEST):
165
    """
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    Update the REQUEST
    """
    extra_context = REQUEST.other.get('erp5_extra_context', {})
    for k, v in self.get_value('extra_context'):
      extra_context[k] = v
    REQUEST.other['erp5_extra_context'] = extra_context
    return REQUEST

  security.declareProtected('Access contents information', 'get_value')
  def get_value(self, id, **kw):
    """Get value for id.

    Optionally pass keyword arguments that get passed to TALES
    expression.
    """
181
    result = None
182 183 184 185 186 187 188
    if id in self.widget.property_names:
      result = ZMIField.get_value(self, id, **kw)
    else:
      proxy_field = self.getTemplateField()
      if proxy_field is not None:
        result = proxy_field.get_value(id, **kw)
    return result
189 190 191 192 193 194 195 196 197 198 199 200 201 202

  security.declareProtected('Access contents information', 'has_value')
  def has_value(self, id):
    """
    Return true if the field defines such a value.
    """
    result = None
    if id in self.widget.property_names:
      result = ZMIField.has_value(self, id)
    else:
      proxy_field = self.getTemplateField()
      if proxy_field is not None:
        result = proxy_field.has_value(id)
    return result