RelationField.py 7.16 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 74 75 76
    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)]

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
77

78
allow_class(RelationEditor)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
79

80
class RelationStringFieldValidator(
Romain Courteaud's avatar
Romain Courteaud committed
81 82
               MultiRelationField.MultiRelationStringFieldValidator,
               Validator.StringValidator):
83 84 85 86 87 88
  """
      Validation includes lookup of relared instances
  """

  message_names = Validator.StringValidator.message_names + \
            MultiRelationField.MultiRelationStringFieldValidator.message_names
Romain Courteaud's avatar
Romain Courteaud committed
89 90 91
  property_names = Validator.StringValidator.property_names + \
          MultiRelationField.MultiRelationStringFieldValidator.property_names

92 93 94 95 96 97 98 99 100
  # 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
101
  
Romain Courteaud's avatar
Romain Courteaud committed
102 103 104 105 106 107 108 109
  _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

110 111 112 113 114
  # Relation field variable
  editor = RelationEditor
  default_validator_instance = Validator.StringValidatorInstance

  def _generateItemUidList(self, field, key, relation_uid_list, REQUEST=None):
115
    """
116
    Generate list of uid, item_key
117
    """
118 119 120 121 122 123 124 125 126 127 128 129 130 131
    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):
132
    """
133
    Generate list of value, item_key
134
    """
135 136 137 138 139 140 141
    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)]
142

Jean-Paul Smets's avatar
Jean-Paul Smets committed
143
RelationStringFieldWidgetInstance = RelationStringFieldWidget()
144
RelationStringFieldValidatorInstance = RelationStringFieldValidator()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
145

146
# Should RelationStringField be a subclass of MultiRelationStringField ?
Jean-Paul Smets's avatar
Jean-Paul Smets committed
147
class RelationStringField(ZMIField):
148 149
  meta_type = "RelationStringField"
  security = ClassSecurityInfo()
Jean-Paul Smets's avatar
Jean-Paul Smets committed
150

151 152
  widget = RelationStringFieldWidgetInstance
  validator = RelationStringFieldValidatorInstance
Jean-Paul Smets's avatar
Jean-Paul Smets committed
153

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

  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:
179
      result = ZMIField.get_value(self, id, REQUEST=REQUEST, **kw)
180
    return result
181 182 183 184

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