RelationField.py 6.67 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
#
# 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
32
from Products.PythonScripts.Utility import allow_class
33
from Products.ERP5Form import MultiRelationField
34
from Products.ERP5Form.MultiRelationField import SUB_FIELD_ID, ITEM_ID
35 36
from AccessControl import ClassSecurityInfo

37 38 39 40 41 42 43 44 45 46 47 48
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
49
  default = Widget.TextWidget.default
50 51

  def _generateRenderValueList(self, field, key, value, REQUEST):
52 53
    if REQUEST.get(
        'read_only_%s' % REQUEST.get(
54
           'field__proxyfield_%s_%s_default' % (field.id, field._p_oid),
55 56 57 58 59 60
           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, [])
61
      return [(Widget.TextWidgetInstance, relation_field_id,
62
               relation_item_list, value, None)]
63 64 65 66 67 68 69 70 71 72

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
73

74
allow_class(RelationEditor)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
75

76
class RelationStringFieldValidator(
Romain Courteaud's avatar
Romain Courteaud committed
77 78
               MultiRelationField.MultiRelationStringFieldValidator,
               Validator.StringValidator):
79 80 81 82 83 84
  """
      Validation includes lookup of relared instances
  """

  message_names = Validator.StringValidator.message_names + \
            MultiRelationField.MultiRelationStringFieldValidator.message_names
Romain Courteaud's avatar
Romain Courteaud committed
85 86 87
  property_names = Validator.StringValidator.property_names + \
          MultiRelationField.MultiRelationStringFieldValidator.property_names

88 89 90 91 92
  # 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:
93
    if message_name not in _v_dict:
94 95 96
      _v_message_name_list.append(message_name)
      _v_dict[message_name] = 1
  message_names = _v_message_name_list
97

Romain Courteaud's avatar
Romain Courteaud committed
98 99 100
  _v_dict = {}
  _v_property_name_list = []
  for property_name in property_names:
101
    if property_name not in _v_dict:
Romain Courteaud's avatar
Romain Courteaud committed
102 103 104 105
      _v_property_name_list.append(property_name)
      _v_dict[property_name] = 1
  property_names = _v_property_name_list

106 107 108 109 110
  # Relation field variable
  editor = RelationEditor
  default_validator_instance = Validator.StringValidatorInstance

  def _generateItemUidList(self, field, key, relation_uid_list, REQUEST=None):
111
    """
112
    Generate list of uid, item_key
113
    """
114 115
    relation_item_id = field.generate_subfield_key(ITEM_ID,
                                                   key=key)
116
    if isinstance(relation_uid_list, (list, tuple)):
117 118 119 120 121
      try:
        relation_uid_list = relation_uid_list[0]
      except IndexError:
        # No object was selected
        return []
122 123

    value = self.default_validator_instance.validate(field, key, REQUEST)
124 125
    return [(relation_item_id, relation_uid_list, value)]

126
  def _generateFieldValueList(self, field, key,
127
                              value_list, current_value_list):
128
    """
129
    Generate list of value, item_key
130
    """
131 132 133 134 135 136 137
    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)]
138

Jean-Paul Smets's avatar
Jean-Paul Smets committed
139
RelationStringFieldWidgetInstance = RelationStringFieldWidget()
140
RelationStringFieldValidatorInstance = RelationStringFieldValidator()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
141

142
# Should RelationStringField be a subclass of MultiRelationStringField ?
Jean-Paul Smets's avatar
Jean-Paul Smets committed
143
class RelationStringField(ZMIField):
144 145
  meta_type = "RelationStringField"
  security = ClassSecurityInfo()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
146

147 148
  widget = RelationStringFieldWidgetInstance
  validator = RelationStringFieldValidatorInstance
Jean-Paul Smets's avatar
Jean-Paul Smets committed
149

150 151
  security.declareProtected('Access contents information', 'get_orig_value')
  def get_orig_value(self, id):
152
    """
153
    Get value for id; don't do any override calculation.
154
    """
155
    if id == 'is_relation_field':
156 157 158 159
      result = 1
    elif id == 'is_multi_relation_field':
      result = 0
    else:
160
      result = ZMIField.get_orig_value(self, id)
161
    return result
162 163 164 165 166 167 168 169 170 171 172 173 174

  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:
175
      result = ZMIField.get_value(self, id, REQUEST=REQUEST, **kw)
176
    return result