14 """ |
14 """ |
15 __docformat__ = "restructuredtext en" |
15 __docformat__ = "restructuredtext en" |
16 |
16 |
17 from logilab.mtconverter import html_escape |
17 from logilab.mtconverter import html_escape |
18 |
18 |
|
19 from cubicweb.rtags import RelationTags |
19 from cubicweb.selectors import match_user_groups, non_final_entity |
20 from cubicweb.selectors import match_user_groups, non_final_entity |
20 from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, BoxHtml, RawBoxItem |
21 from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, BoxHtml, RawBoxItem |
21 from cubicweb.view import EntityView |
22 from cubicweb.view import EntityView |
22 from cubicweb.web.box import BoxTemplate |
23 from cubicweb.web.box import BoxTemplate |
23 |
24 |
27 class EditBox(BoxTemplate): |
28 class EditBox(BoxTemplate): |
28 """ |
29 """ |
29 box with all actions impacting the entity displayed: edit, copy, delete |
30 box with all actions impacting the entity displayed: edit, copy, delete |
30 change state, add related entities |
31 change state, add related entities |
31 """ |
32 """ |
|
33 id = 'edit_box' |
32 __select__ = BoxTemplate.__select__ & non_final_entity() |
34 __select__ = BoxTemplate.__select__ & non_final_entity() |
33 id = 'edit_box' |
35 |
34 title = _('actions') |
36 title = _('actions') |
35 order = 2 |
37 order = 2 |
|
38 # 'link' / 'create' relation tags, used to control the "add entity" submenu |
|
39 rmode = RelationTags() |
|
40 |
|
41 @classmethod |
|
42 def registered(cls, registry): |
|
43 """build class using descriptor at registration time""" |
|
44 super(AutomaticEntityForm, cls).registered(registry) |
|
45 cls.init_rtags_mode() |
|
46 return cls |
|
47 |
|
48 @classmethod |
|
49 def init_rtags_mode(cls): |
|
50 """set default category tags for relations where it's not yet defined in |
|
51 the category relation tags |
|
52 """ |
|
53 for eschema in cls.schema.entities(): |
|
54 for rschema, tschemas, role in eschema.relation_definitions(True): |
|
55 for tschema in tschemas: |
|
56 if role == 'subject': |
|
57 X, Y = eschema, tschema |
|
58 card = rschema.rproperty(X, Y, 'cardinality')[0] |
|
59 else: |
|
60 X, Y = tschema, eschema |
|
61 card = rschema.rproperty(X, Y, 'cardinality')[1] |
|
62 if not cls.rmode.rtag(role, rschema, X, Y): |
|
63 if card in '?1': |
|
64 # by default, suppose link mode if cardinality doesn't allow |
|
65 # more than one relation |
|
66 mode = 'link' |
|
67 elif rschema.rproperty(X, Y, 'composite') == role: |
|
68 # if self is composed of the target type, create mode |
|
69 mode = 'create' |
|
70 else: |
|
71 # link mode by default |
|
72 mode = 'link' |
|
73 cls.rmode.set_rtag(category, role, rschema, X, Y) |
|
74 |
|
75 @classmethod |
|
76 def relation_mode(cls, rtype, etype, targettype, role='subject'): |
|
77 """return a string telling if the given relation is usually created |
|
78 to a new entity ('create' mode) or to an existant entity ('link' mode) |
|
79 """ |
|
80 return cls.rmode.rtag(role, rtype, etype, targettype) |
|
81 |
36 |
82 |
37 def call(self, **kwargs): |
83 def call(self, **kwargs): |
38 _ = self.req._ |
84 _ = self.req._ |
39 title = _(self.title) |
85 title = _(self.title) |
40 if self.rset: |
86 if self.rset: |
90 def schema_actions(self, entity): |
136 def schema_actions(self, entity): |
91 user = self.req.user |
137 user = self.req.user |
92 actions = [] |
138 actions = [] |
93 _ = self.req._ |
139 _ = self.req._ |
94 eschema = entity.e_schema |
140 eschema = entity.e_schema |
95 for rschema, teschema, x in entity.add_related_schemas(): |
141 for rschema, teschema, x in self.add_related_schemas(entity): |
96 if x == 'subject': |
142 if x == 'subject': |
97 label = 'add %s %s %s %s' % (eschema, rschema, teschema, x) |
143 label = 'add %s %s %s %s' % (eschema, rschema, teschema, x) |
98 url = self.linkto_url(entity, rschema, teschema, 'object') |
144 url = self.linkto_url(entity, rschema, teschema, 'object') |
99 else: |
145 else: |
100 label = 'add %s %s %s %s' % (teschema, rschema, eschema, x) |
146 label = 'add %s %s %s %s' % (teschema, rschema, eschema, x) |
101 url = self.linkto_url(entity, rschema, teschema, 'subject') |
147 url = self.linkto_url(entity, rschema, teschema, 'subject') |
102 actions.append(self.mk_action(_(label), url)) |
148 actions.append(self.mk_action(_(label), url)) |
103 return actions |
149 return actions |
|
150 |
|
151 def add_related_schemas(self, entity): |
|
152 """this is actually used ui method to generate 'addrelated' actions from |
|
153 the schema. |
|
154 |
|
155 If you're using explicit 'addrelated' actions for an entity types, you |
|
156 should probably overrides this method to return an empty list else you |
|
157 may get some unexpected actions. |
|
158 """ |
|
159 req = self.req |
|
160 eschema = entity.e_schema |
|
161 for role, rschemas in (('subject', eschema.subject_relations()), |
|
162 ('object', eschema.object_relations())): |
|
163 for rschema in rschemas: |
|
164 if rschema.is_final(): |
|
165 continue |
|
166 # check the relation can be added as well |
|
167 if role == 'subject'and not rschema.has_perm(req, 'add', fromeid=entity.eid): |
|
168 continue |
|
169 if role == 'object'and not rschema.has_perm(req, 'add', toeid=entity.eid): |
|
170 continue |
|
171 # check the target types can be added as well |
|
172 for teschema in rschema.targets(eschema, role): |
|
173 if not self.relation_mode(rschema, eschema, teschema, role) == 'create': |
|
174 continue |
|
175 if teschema.has_local_role('add') or teschema.has_perm(req, 'add'): |
|
176 yield rschema, teschema, role |
104 |
177 |
105 |
178 |
106 def workflow_actions(self, entity, box): |
179 def workflow_actions(self, entity, box): |
107 if 'in_state' in entity.e_schema.subject_relations() and entity.in_state: |
180 if 'in_state' in entity.e_schema.subject_relations() and entity.in_state: |
108 _ = self.req._ |
181 _ = self.req._ |