diff -r 1e19b6ef53a1 -r 2d1b721fded9 web/views/boxes.py --- a/web/views/boxes.py Thu Mar 26 19:00:20 2009 +0100 +++ b/web/views/boxes.py Thu Mar 26 19:15:57 2009 +0100 @@ -16,6 +16,7 @@ from logilab.mtconverter import html_escape +from cubicweb.rtags import RelationTags from cubicweb.selectors import match_user_groups, non_final_entity from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, BoxHtml, RawBoxItem from cubicweb.view import EntityView @@ -29,10 +30,55 @@ box with all actions impacting the entity displayed: edit, copy, delete change state, add related entities """ + id = 'edit_box' __select__ = BoxTemplate.__select__ & non_final_entity() - id = 'edit_box' + title = _('actions') order = 2 + # 'link' / 'create' relation tags, used to control the "add entity" submenu + rmode = RelationTags() + + @classmethod + def registered(cls, registry): + """build class using descriptor at registration time""" + super(AutomaticEntityForm, cls).registered(registry) + cls.init_rtags_mode() + return cls + + @classmethod + def init_rtags_mode(cls): + """set default category tags for relations where it's not yet defined in + the category relation tags + """ + for eschema in cls.schema.entities(): + for rschema, tschemas, role in eschema.relation_definitions(True): + for tschema in tschemas: + if role == 'subject': + X, Y = eschema, tschema + card = rschema.rproperty(X, Y, 'cardinality')[0] + else: + X, Y = tschema, eschema + card = rschema.rproperty(X, Y, 'cardinality')[1] + if not cls.rmode.rtag(role, rschema, X, Y): + if card in '?1': + # by default, suppose link mode if cardinality doesn't allow + # more than one relation + mode = 'link' + elif rschema.rproperty(X, Y, 'composite') == role: + # if self is composed of the target type, create mode + mode = 'create' + else: + # link mode by default + mode = 'link' + cls.rmode.set_rtag(category, role, rschema, X, Y) + + @classmethod + def relation_mode(cls, rtype, etype, targettype, role='subject'): + """return a string telling if the given relation is usually created + to a new entity ('create' mode) or to an existant entity ('link' mode) + """ + return cls.rmode.rtag(role, rtype, etype, targettype) + def call(self, **kwargs): _ = self.req._ @@ -92,7 +138,7 @@ actions = [] _ = self.req._ eschema = entity.e_schema - for rschema, teschema, x in entity.add_related_schemas(): + for rschema, teschema, x in self.add_related_schemas(entity): if x == 'subject': label = 'add %s %s %s %s' % (eschema, rschema, teschema, x) url = self.linkto_url(entity, rschema, teschema, 'object') @@ -102,6 +148,33 @@ actions.append(self.mk_action(_(label), url)) return actions + def add_related_schemas(self, entity): + """this is actually used ui method to generate 'addrelated' actions from + the schema. + + If you're using explicit 'addrelated' actions for an entity types, you + should probably overrides this method to return an empty list else you + may get some unexpected actions. + """ + req = self.req + eschema = entity.e_schema + for role, rschemas in (('subject', eschema.subject_relations()), + ('object', eschema.object_relations())): + for rschema in rschemas: + if rschema.is_final(): + continue + # check the relation can be added as well + if role == 'subject'and not rschema.has_perm(req, 'add', fromeid=entity.eid): + continue + if role == 'object'and not rschema.has_perm(req, 'add', toeid=entity.eid): + continue + # check the target types can be added as well + for teschema in rschema.targets(eschema, role): + if not self.relation_mode(rschema, eschema, teschema, role) == 'create': + continue + if teschema.has_local_role('add') or teschema.has_perm(req, 'add'): + yield rschema, teschema, role + def workflow_actions(self, entity, box): if 'in_state' in entity.e_schema.subject_relations() and entity.in_state: