RelationField.py 7.36 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2
##############################################################################
#
3
# Copyright (c) 2002, 2006 Nexedi SARL and Contributors. All Rights Reserved.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
4
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
5
#                    Romain Courteaud <romain@nexedi.com>
Jean-Paul Smets's avatar
Jean-Paul Smets committed
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
#
# 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.ERP5Type.Utils import convertToUpperCase
34
from Products.CMFCore.utils import getToolByName
35
from Products.PythonScripts.Utility import allow_class
36
from Products.ERP5Type.Message import Message
37 38 39
from Products.ERP5Form import MultiRelationField
from Products.ERP5Form.MultiRelationField import MAX_SELECT, \
                                            NEW_CONTENT_PREFIX, \
Romain Courteaud's avatar
Romain Courteaud committed
40 41
                                            SUB_FIELD_ID, ITEM_ID, \
                                            NO_VALUE
42
from types import StringType
43
from AccessControl import ClassSecurityInfo
Sebastien Robin's avatar
Sebastien Robin committed
44
from zLOG import LOG
45

46 47 48 49 50 51 52 53 54 55 56 57
class RelationStringFieldWidget(
                  MultiRelationField.MultiRelationStringFieldWidget):
  """
  RelationStringField widget
  Works like a string field but includes one buttons
  - one search button which updates the field and sets a relation
  - creates object if not there
  """
  property_names = Widget.TextWidget.property_names + \
       MultiRelationField.MultiRelationStringFieldWidget.local_property_names

  default_widget_rendering_instance = Widget.TextWidgetInstance
58
  default = Widget.TextWidget.default
59 60

  def _generateRenderValueList(self, field, key, value, REQUEST):
Romain Courteaud's avatar
Romain Courteaud committed
61
#     value = value or NO_VALUE
62 63 64 65 66 67 68 69 70 71 72 73

    if REQUEST.get(
        'read_only_%s' % REQUEST.get(
           'field__proxyfield_%s_%s_default' % (field.id, field._p_oid), 
           field).getId()[3:], 0):
      return []
    else:
      relation_field_id = field.generate_subfield_key(SUB_FIELD_ID, key=key)
      relation_item_key = field.generate_subfield_key(ITEM_ID, key=key)
      relation_item_list = REQUEST.get(relation_item_key, [])
      return [(Widget.TextWidgetInstance, relation_field_id, 
               relation_item_list, value, None)]
74 75 76 77 78 79 80 81 82 83

class RelationEditor(MultiRelationField.MultiRelationEditor):
  """
  A class holding all values required to update a relation
  """
  def __call__(self, REQUEST):
    MultiRelationField.MultiRelationEditor.__call__(self, REQUEST)
    value = REQUEST.get(self.field_id)
    if value is not None:
      REQUEST.set(self.field_id, value[0])
Jean-Paul Smets's avatar
Jean-Paul Smets committed
84

85
allow_class(RelationEditor)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
86

87
class RelationStringFieldValidator(
Romain Courteaud's avatar
Romain Courteaud committed
88 89
               MultiRelationField.MultiRelationStringFieldValidator,
               Validator.StringValidator):
90 91 92 93 94 95
  """
      Validation includes lookup of relared instances
  """

  message_names = Validator.StringValidator.message_names + \
            MultiRelationField.MultiRelationStringFieldValidator.message_names
Romain Courteaud's avatar
Romain Courteaud committed
96 97 98
  property_names = Validator.StringValidator.property_names + \
          MultiRelationField.MultiRelationStringFieldValidator.property_names

99 100 101 102 103 104 105 106 107
  # Delete double in order to keep a usable ZMI...
  # Need to keep order !
  _v_dict = {}
  _v_message_name_list = []
  for message_name in message_names:
    if not _v_dict.has_key(message_name):
      _v_message_name_list.append(message_name)
      _v_dict[message_name] = 1
  message_names = _v_message_name_list
108
  
Romain Courteaud's avatar
Romain Courteaud committed
109 110 111 112 113 114 115 116
  _v_dict = {}
  _v_property_name_list = []
  for property_name in property_names:
    if not _v_dict.has_key(property_name):
      _v_property_name_list.append(property_name)
      _v_dict[property_name] = 1
  property_names = _v_property_name_list

117 118 119 120 121
  # Relation field variable
  editor = RelationEditor
  default_validator_instance = Validator.StringValidatorInstance

  def _generateItemUidList(self, field, key, relation_uid_list, REQUEST=None):
122
    """
123
    Generate list of uid, item_key
124
    """
125 126 127 128 129 130 131 132 133 134 135 136 137 138
    relation_item_id = field.generate_subfield_key(ITEM_ID,
                                                   key=key)
    if isinstance(relation_uid_list, (list, tuple)):
      try:
        relation_uid_list = relation_uid_list[0]
      except IndexError:
        # No object was selected
        return []
    value = self.default_validator_instance.validate(field, 
                                                     key, REQUEST)
    return [(relation_item_id, relation_uid_list, value)]

  def _generateFieldValueList(self, field, key, 
                              value_list, current_value_list):
139
    """
140
    Generate list of value, item_key
141
    """
142 143 144 145 146 147 148
    if value_list == current_value_list:
      return []
    else:
      relation_field_id = field.generate_subfield_key("%s" % \
                                                      SUB_FIELD_ID, key=key)
      relation_item_key = field.generate_subfield_key(ITEM_ID, key=key)
      return [(relation_field_id, value_list, relation_item_key)]
149

Jean-Paul Smets's avatar
Jean-Paul Smets committed
150
RelationStringFieldWidgetInstance = RelationStringFieldWidget()
151
RelationStringFieldValidatorInstance = RelationStringFieldValidator()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
152

153
# Should RelationStringField be a subclass of MultiRelationStringField ?
Jean-Paul Smets's avatar
Jean-Paul Smets committed
154
class RelationStringField(ZMIField):
155 156
  meta_type = "RelationStringField"
  security = ClassSecurityInfo()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
157

158 159
  widget = RelationStringFieldWidgetInstance
  validator = RelationStringFieldValidatorInstance
Jean-Paul Smets's avatar
Jean-Paul Smets committed
160

161 162
  security.declareProtected('Access contents information', 'get_orig_value')
  def get_orig_value(self, id):
163
    """
164
    Get value for id; don't do any override calculation.
165
    """
166
    if id == 'is_relation_field': 
167 168 169 170
      result = 1
    elif id == 'is_multi_relation_field':
      result = 0
    else:
171
      result = ZMIField.get_orig_value(self, id)
172
    return result
173 174 175 176 177 178 179 180 181 182 183 184 185

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

    Optionally pass keyword arguments that get passed to TALES
    expression.
    """
    # XXX FIXME Same code as MultiRelationStringField
    if (id == 'items') and (REQUEST is not None):
      # relation_item_list is not editable for the RelationField
      result = REQUEST.get('relation_item_list', None)
    else:
186
      result = ZMIField.get_value(self, id, REQUEST=REQUEST, **kw)
187
    return result
188 189 190 191

# Register get_value
from Products.ERP5Form.ProxyField import registerOriginalGetValueClassAndArgument
registerOriginalGetValueClassAndArgument(RelationStringField, 'items')