1016 # error when processed by the editcontroller : it may be marked as required |
1016 # error when processed by the editcontroller : it may be marked as required |
1017 # while it has no value, hence generating a false error. |
1017 # while it has no value, hence generating a false error. |
1018 return list(self.fields) |
1018 return list(self.fields) |
1019 |
1019 |
1020 |
1020 |
1021 # relation vocabulary helper functions ######################################### |
|
1022 |
|
1023 def relvoc_linkedto(entity, rtype, role): |
|
1024 # first see if its specified by __linkto form parameters |
|
1025 linkedto = entity.linked_to(rtype, role) |
|
1026 if linkedto: |
|
1027 buildent = entity._cw.entity_from_eid |
|
1028 return [(buildent(eid).view('combobox'), unicode(eid)) for eid in linkedto] |
|
1029 return [] |
|
1030 |
|
1031 def relvoc_init(entity, rtype, role, required=False): |
|
1032 # it isn't, check if the entity provides a method to get correct values |
|
1033 vocab = [] |
|
1034 if not required: |
|
1035 vocab.append(('', INTERNAL_FIELD_VALUE)) |
|
1036 # vocabulary doesn't include current values, add them |
|
1037 if entity.has_eid(): |
|
1038 rset = entity.related(rtype, role) |
|
1039 vocab += [(e.view('combobox'), unicode(e.eid)) for e in rset.entities()] |
|
1040 return vocab |
|
1041 |
|
1042 def relvoc_unrelated(entity, rtype, role, limit=None): |
|
1043 if isinstance(rtype, basestring): |
|
1044 rtype = entity._cw.vreg.schema.rschema(rtype) |
|
1045 if entity.has_eid(): |
|
1046 done = set(row[0] for row in entity.related(rtype, role)) |
|
1047 else: |
|
1048 done = None |
|
1049 result = [] |
|
1050 rsetsize = None |
|
1051 for objtype in rtype.targets(entity.e_schema, role): |
|
1052 if limit is not None: |
|
1053 rsetsize = limit - len(result) |
|
1054 result += _relvoc_unrelated(entity, rtype, objtype, role, rsetsize, done) |
|
1055 if limit is not None and len(result) >= limit: |
|
1056 break |
|
1057 return result |
|
1058 |
|
1059 def _relvoc_unrelated(entity, rtype, targettype, role, limit, done): |
|
1060 """return unrelated entities for a given relation and target entity type |
|
1061 for use in vocabulary |
|
1062 """ |
|
1063 if done is None: |
|
1064 done = set() |
|
1065 res = [] |
|
1066 for entity in entity.unrelated(rtype, targettype, role, limit).entities(): |
|
1067 if entity.eid in done: |
|
1068 continue |
|
1069 done.add(entity.eid) |
|
1070 res.append((entity.view('combobox'), unicode(entity.eid))) |
|
1071 return res |
|
1072 |
|
1073 |
|
1074 class RelationField(Field): |
1021 class RelationField(Field): |
1075 """Use this field to edit a relation of an entity. |
1022 """Use this field to edit a relation of an entity. |
1076 |
1023 |
1077 Unless explicitly specified, the widget for this field will be a |
1024 Unless explicitly specified, the widget for this field will be a |
1078 :class:`~cubicweb.web.formwidgets.Select`. |
1025 :class:`~cubicweb.web.formwidgets.Select`. |
1093 * have a max size of `limit` entities |
1040 * have a max size of `limit` entities |
1094 """ |
1041 """ |
1095 entity = form.edited_entity |
1042 entity = form.edited_entity |
1096 # first see if its specified by __linkto form parameters |
1043 # first see if its specified by __linkto form parameters |
1097 if limit is None: |
1044 if limit is None: |
1098 linkedto = relvoc_linkedto(entity, self.name, self.role) |
1045 linkedto = self.relvoc_linkedto(form) |
1099 if linkedto: |
1046 if linkedto: |
1100 return linkedto |
1047 return linkedto |
1101 vocab = relvoc_init(entity, self.name, self.role, self.required) |
1048 vocab = self.relvoc_init(form) |
1102 else: |
1049 else: |
1103 vocab = [] |
1050 vocab = [] |
1104 # it isn't, check if the entity provides a method to get correct values |
1051 # it isn't, check if the entity provides a method to get correct values |
1105 method = '%s_%s_vocabulary' % (self.role, self.name) |
1052 method = '%s_%s_vocabulary' % (self.role, self.name) |
1106 try: |
1053 try: |
1107 vocab += getattr(form, method)(self.name, limit) |
1054 vocab += getattr(form, method)(self.name, limit) |
1108 warn('[3.6] found %s on %s, should override field.choices instead (need tweaks)' |
1055 warn('[3.6] found %s on %s, should override field.choices instead (need tweaks)' |
1109 % (method, form), DeprecationWarning) |
1056 % (method, form), DeprecationWarning) |
1110 except AttributeError: |
1057 except AttributeError: |
1111 vocab += relvoc_unrelated(entity, self.name, self.role, limit) |
1058 vocab += self.relvoc_unrelated(form, limit) |
1112 if self.sort: |
1059 if self.sort: |
1113 vocab = vocab_sort(vocab) |
1060 vocab = vocab_sort(vocab) |
1114 return vocab |
1061 return vocab |
1115 |
1062 |
1116 def form_init(self, form): |
1063 def relvoc_linkedto(self, form): |
1117 #if not self.display_value(form): |
1064 linkedto = form.linked_to.get((self.name, self.role)) |
1118 value = form.edited_entity.linked_to(self.name, self.role) |
1065 if linkedto: |
1119 if value: |
1066 buildent = form._cw.entity_from_eid |
1120 searchedvalues = ['%s:%s:%s' % (self.name, eid, self.role) |
1067 return [(buildent(eid).view('combobox'), unicode(eid)) |
1121 for eid in value] |
1068 for eid in linkedto] |
1122 # remove associated __linkto hidden fields |
1069 return [] |
1123 for field in form.root_form.fields_by_name('__linkto'): |
1070 |
1124 if field.value in searchedvalues: |
1071 def relvoc_init(self, form): |
1125 form.root_form.remove_field(field) |
1072 entity, rtype, role = form.edited_entity, self.name, self.role |
1126 form.formvalues[(self, form)] = value |
1073 vocab = [] |
|
1074 if not self.required: |
|
1075 vocab.append(('', INTERNAL_FIELD_VALUE)) |
|
1076 # vocabulary doesn't include current values, add them |
|
1077 if form.edited_entity.has_eid(): |
|
1078 rset = form.edited_entity.related(self.name, self.role) |
|
1079 vocab += [(e.view('combobox'), unicode(e.eid)) |
|
1080 for e in rset.entities()] |
|
1081 return vocab |
|
1082 |
|
1083 def relvoc_unrelated(self, form, limit=None): |
|
1084 entity = form.edited_entity |
|
1085 rtype = entity._cw.vreg.schema.rschema(self.name) |
|
1086 if entity.has_eid(): |
|
1087 done = set(row[0] for row in entity.related(rtype, self.role)) |
|
1088 else: |
|
1089 done = None |
|
1090 result = [] |
|
1091 rsetsize = None |
|
1092 for objtype in rtype.targets(entity.e_schema, self.role): |
|
1093 if limit is not None: |
|
1094 rsetsize = limit - len(result) |
|
1095 result += self._relvoc_unrelated(form, objtype, rsetsize, done) |
|
1096 if limit is not None and len(result) >= limit: |
|
1097 break |
|
1098 return result |
|
1099 |
|
1100 def _relvoc_unrelated(self, form, targettype, limit, done): |
|
1101 """return unrelated entities for a given relation and target entity type |
|
1102 for use in vocabulary |
|
1103 """ |
|
1104 if done is None: |
|
1105 done = set() |
|
1106 res = [] |
|
1107 entity = form.edited_entity |
|
1108 for entity in entity.unrelated(self.name, targettype, |
|
1109 self.role, limit).entities(): |
|
1110 if entity.eid in done: |
|
1111 continue |
|
1112 done.add(entity.eid) |
|
1113 res.append((entity.view('combobox'), unicode(entity.eid))) |
|
1114 return res |
1127 |
1115 |
1128 def format_single_value(self, req, value): |
1116 def format_single_value(self, req, value): |
1129 return unicode(value) |
1117 return unicode(value) |
1130 |
1118 |
1131 def process_form_value(self, form): |
1119 def process_form_value(self, form): |