10 |
10 |
11 from logilab.common.ureports import Section, Title, Table, Link, Span, Text |
11 from logilab.common.ureports import Section, Title, Table, Link, Span, Text |
12 |
12 |
13 from yams.schema2dot import CARD_MAP |
13 from yams.schema2dot import CARD_MAP |
14 from yams.schema import RelationDefinitionSchema |
14 from yams.schema import RelationDefinitionSchema |
|
15 from operator import attrgetter |
|
16 |
|
17 TYPE_GETTER = attrgetter('type') |
15 |
18 |
16 I18NSTRINGS = [_('read'), _('add'), _('delete'), _('update'), _('order')] |
19 I18NSTRINGS = [_('read'), _('add'), _('delete'), _('update'), _('order')] |
17 |
20 |
18 |
21 |
19 class SchemaViewer(object): |
22 class SchemaViewer(object): |
20 """return an ureport layout for some part of a schema""" |
23 """return an ureport layout for some part of a schema""" |
21 def __init__(self, req=None, encoding=None): |
24 def __init__(self, req=None, encoding=None): |
22 self.req = req |
25 self.req = req |
23 if req is not None: |
26 if req is not None: |
24 self.req.add_css('cubicweb.schema.css') |
27 req.add_css('cubicweb.schema.css') |
25 if not encoding: |
28 if encoding is None: |
26 encoding = req.encoding |
29 encoding = req.encoding |
|
30 self._ = req._ |
|
31 else: |
|
32 encoding = 'ascii' |
|
33 self._ = unicode |
27 self.encoding = encoding |
34 self.encoding = encoding |
|
35 |
|
36 # no self.req managements |
|
37 |
|
38 def may_read(self, rdef, action): |
|
39 """Return true if request user may read the given schema. |
|
40 Always return True when no request is provided. |
|
41 """ |
|
42 if self.req is None: |
|
43 return True |
|
44 return sch.may_have_permission('read', self.req) |
|
45 |
|
46 def format_eschema(self, eschema): |
|
47 text = eschema.type |
|
48 if self.req is None: |
|
49 return Text(text) |
|
50 return Link(self.req.build_url('cwetype/%s' % eschema), text) |
|
51 |
|
52 def format_rschema(self, rschema, label=None): |
|
53 if label is None: |
|
54 label = rschema.type |
|
55 if self.req is None: |
|
56 return Text(label) |
|
57 return Link(self.req.build_url('cwrtype/%s' % rschema), label) |
|
58 |
|
59 # end of no self.req managements |
28 |
60 |
29 def visit_schema(self, schema, display_relations=0, skiptypes=()): |
61 def visit_schema(self, schema, display_relations=0, skiptypes=()): |
30 """get a layout for a whole schema""" |
62 """get a layout for a whole schema""" |
31 title = Title(self.req._('Schema %s') % schema.name, |
63 title = Title(self._('Schema %s') % schema.name, |
32 klass='titleUnderline') |
64 klass='titleUnderline') |
33 layout = Section(children=(title,)) |
65 layout = Section(children=(title,)) |
34 esection = Section(children=(Title(self.req._('Entities'), |
66 esection = Section(children=(Title(self._('Entities'), |
35 klass='titleUnderline'),)) |
67 klass='titleUnderline'),)) |
36 layout.append(esection) |
68 layout.append(esection) |
37 eschemas = [eschema for eschema in schema.entities() |
69 eschemas = [eschema for eschema in schema.entities() |
38 if not (eschema.final or eschema in skiptypes)] |
70 if not (eschema.final or eschema in skiptypes)] |
39 for eschema in sorted(eschemas): |
71 for eschema in sorted(eschemas, key=TYPE_GETTER): |
40 esection.append(self.visit_entityschema(eschema, skiptypes)) |
72 esection.append(self.visit_entityschema(eschema, skiptypes)) |
41 if display_relations: |
73 if display_relations: |
42 title = Title(self.req._('Relations'), klass='titleUnderline') |
74 title = Title(self._('Relations'), klass='titleUnderline') |
43 rsection = Section(children=(title,)) |
75 rsection = Section(children=(title,)) |
44 layout.append(rsection) |
76 layout.append(rsection) |
45 relations = [rschema for rschema in schema.relations() |
77 relations = [rschema for rschema in sorted(schema.relations(), key=TYPE_GETTER) |
46 if not (rschema.final or rschema.type in skiptypes)] |
78 if not (rschema.final or rschema.type in skiptypes)] |
47 keys = [(rschema.type, rschema) for rschema in relations] |
79 keys = [(rschema.type, rschema) for rschema in relations] |
48 for key, rschema in sorted(keys): |
80 for key, rschema in sorted(keys, cmp=(lambda x, y: cmp(x[1], y[1]))): |
49 relstr = self.visit_relationschema(rschema) |
81 relstr = self.visit_relationschema(rschema) |
50 rsection.append(relstr) |
82 rsection.append(relstr) |
51 return layout |
83 return layout |
52 |
84 |
53 def _entity_attributes_data(self, eschema): |
85 def _entity_attributes_data(self, eschema): |
54 _ = self.req._ |
86 _ = self._ |
55 data = [_('attribute'), _('type'), _('default'), _('constraints')] |
87 data = [_('attribute'), _('type'), _('default'), _('constraints')] |
56 for rschema, aschema in eschema.attribute_definitions(): |
88 attributes = sorted(eschema.attribute_definitions(), cmp=(lambda x, y: cmp(x[0].type, y[0].type))) |
|
89 for rschema, aschema in attributes: |
57 rdef = eschema.rdef(rschema) |
90 rdef = eschema.rdef(rschema) |
58 if not rdef.may_have_permission('read', self.req): |
91 if not self.may_read(rdef): |
59 continue |
92 continue |
60 aname = rschema.type |
93 aname = rschema.type |
61 if aname == 'eid': |
94 if aname == 'eid': |
62 continue |
95 continue |
63 data.append('%s (%s)' % (aname, _(aname))) |
96 data.append('%s (%s)' % (aname, _(aname))) |
73 constraints = rschema.rproperty(eschema.type, aschema.type, |
106 constraints = rschema.rproperty(eschema.type, aschema.type, |
74 'constraints') |
107 'constraints') |
75 data.append(', '.join(str(constr) for constr in constraints)) |
108 data.append(', '.join(str(constr) for constr in constraints)) |
76 return data |
109 return data |
77 |
110 |
78 def eschema_link_url(self, eschema): |
|
79 return self.req.build_url('cwetype/%s' % eschema) |
|
80 |
|
81 def rschema_link_url(self, rschema): |
|
82 return self.req.build_url('cwrtype/%s' % rschema) |
|
83 |
111 |
84 def stereotype(self, name): |
112 def stereotype(self, name): |
85 return Span((' <<%s>>' % name,), klass='stereotype') |
113 return Span((' <<%s>>' % name,), klass='stereotype') |
86 |
114 |
87 def visit_entityschema(self, eschema, skiptypes=()): |
115 def visit_entityschema(self, eschema, skiptypes=()): |
88 """get a layout for an entity schema""" |
116 """get a layout for an entity schema""" |
89 etype = eschema.type |
117 etype = eschema.type |
90 layout = Section(children=' ', klass='clear') |
118 layout = Section(children=' ', klass='clear') |
91 layout.append(Link(etype,' ' , id=etype)) # anchor |
119 layout.append(Link(etype,' ' , id=etype)) # anchor |
92 title = Link(self.eschema_link_url(eschema), etype) |
120 title = self.format_eschema(eschema) |
93 boxchild = [Section(children=(title,), klass='title')] |
121 boxchild = [Section(children=(title,), klass='title')] |
94 data = [] |
122 data = [] |
95 data.append(Section(children=boxchild, klass='box')) |
123 data.append(Section(children=boxchild, klass='box')) |
96 data.append(Section(children='', klass='vl')) |
124 data.append(Section(children='', klass='vl')) |
97 data.append(Section(children='', klass='hl')) |
125 data.append(Section(children='', klass='hl')) |
98 t_vars = [] |
126 t_vars = [] |
99 rels = [] |
127 rels = [] |
100 first = True |
128 first = True |
101 for rschema, targetschemas, role in eschema.relation_definitions(): |
129 |
|
130 rel_defs = sorted(eschema.relation_definitions(), |
|
131 cmp=(lambda x, y: cmp((x[0].type, x[0].cardinality), |
|
132 (y[0].type, y[0].cardinality)))) |
|
133 for rschema, targetschemas, role in rel_defs: |
102 if rschema.type in skiptypes: |
134 if rschema.type in skiptypes: |
103 continue |
135 continue |
104 rschemaurl = self.rschema_link_url(rschema) |
136 for oeschema in sorted(targetschemas, key=TYPE_GETTER): |
105 for oeschema in targetschemas: |
|
106 rdef = rschema.role_rdef(eschema, oeschema, role) |
137 rdef = rschema.role_rdef(eschema, oeschema, role) |
107 if not rdef.may_have_permission('read', self.req): |
138 if not self.may_read(rdef): |
108 continue |
139 continue |
109 label = rschema.type |
140 label = rschema.type |
110 if role == 'subject': |
141 if role == 'subject': |
111 cards = rschema.rproperty(eschema, oeschema, 'cardinality') |
142 cards = rschema.rproperty(eschema, oeschema, 'cardinality') |
112 else: |
143 else: |
113 cards = rschema.rproperty(oeschema, eschema, 'cardinality') |
144 cards = rschema.rproperty(oeschema, eschema, 'cardinality') |
114 cards = cards[::-1] |
145 cards = cards[::-1] |
115 label = '%s %s %s' % (CARD_MAP[cards[1]], label, |
146 label = '%s %s %s' % (CARD_MAP[cards[1]], label, |
116 CARD_MAP[cards[0]]) |
147 CARD_MAP[cards[0]]) |
117 rlink = Link(rschemaurl, label) |
148 rlink = self.format_rschema(rschema, label) |
118 elink = Link(self.eschema_link_url(oeschema), oeschema.type) |
149 elink = self.format_eschema(oeschema) |
119 if first: |
150 if first: |
120 t_vars.append(Section(children=(elink,), klass='firstvar')) |
151 t_vars.append(Section(children=(elink,), klass='firstvar')) |
121 rels.append(Section(children=(rlink,), klass='firstrel')) |
152 rels.append(Section(children=(rlink,), klass='firstrel')) |
122 first = False |
153 first = False |
123 else: |
154 else: |
128 layout.append(Section(children=data, klass='entityAttributes')) |
159 layout.append(Section(children=data, klass='entityAttributes')) |
129 return layout |
160 return layout |
130 |
161 |
131 def visit_relationschema(self, rschema, title=True): |
162 def visit_relationschema(self, rschema, title=True): |
132 """get a layout for a relation schema""" |
163 """get a layout for a relation schema""" |
133 _ = self.req._ |
164 _ = self._ |
134 if title: |
165 if title: |
135 title = Link(self.rschema_link_url(rschema), rschema.type) |
166 title = self.format_rschema(rschema) |
136 stereotypes = [] |
167 stereotypes = [] |
137 if rschema.meta: |
168 if rschema.meta: |
138 stereotypes.append('meta') |
169 stereotypes.append('meta') |
139 if rschema.symmetric: |
170 if rschema.symmetric: |
140 stereotypes.append('symmetric') |
171 stereotypes.append('symmetric') |
141 if rschema.inlined: |
172 if rschema.inlined: |
142 stereotypes.append('inlined') |
173 stereotypes.append('inlined') |
143 title = Section(children=(title, ' (%s)'%rschema.display_name(self.req)), klass='title') |
174 title = Section(children=(title,), klass='title') |
144 if stereotypes: |
175 if stereotypes: |
145 title.append(self.stereotype(','.join(stereotypes))) |
176 title.append(self.stereotype(','.join(stereotypes))) |
146 layout = Section(children=(title,), klass='schema') |
177 layout = Section(children=(title,), klass='schema') |
147 else: |
178 else: |
148 layout = Section(klass='schema') |
179 layout = Section(klass='schema') |
156 else: |
187 else: |
157 properties = [] |
188 properties = [] |
158 data += [_(prop) for prop in properties] |
189 data += [_(prop) for prop in properties] |
159 cols = len(data) |
190 cols = len(data) |
160 done = set() |
191 done = set() |
161 for subjtype, objtypes in rschema.associations(): |
192 for subjtype, objtypes in sorted(rschema.associations()): |
162 for objtype in objtypes: |
193 for objtype in objtypes: |
163 if (subjtype, objtype) in done: |
194 if (subjtype, objtype) in done: |
164 continue |
195 continue |
165 done.add((subjtype, objtype)) |
196 done.add((subjtype, objtype)) |
166 if rschema.symmetric: |
197 if rschema.symmetric: |
167 done.add((objtype, subjtype)) |
198 done.add((objtype, subjtype)) |
168 data.append(Link(self.eschema_link_url(schema[subjtype]), subjtype)) |
199 data.append(self.format_eschema(schema[subjtype])) |
169 data.append(Link(self.eschema_link_url(schema[objtype]), objtype)) |
200 data.append(self.format_eschema(schema[objtype])) |
170 rdef = rschema.rdef(subjtype, objtype) |
201 rdef = rschema.rdef(subjtype, objtype) |
171 for prop in properties: |
202 for prop in properties: |
172 val = getattr(rdef, prop) |
203 val = getattr(rdef, prop) |
173 if val is None: |
204 if val is None: |
174 val = '' |
205 val = '' |
175 elif prop == 'constraints': |
206 elif prop == 'constraints': |
176 val = ', '.join([c.restriction for c in val]) |
207 val = ', '.join([c.restriction for c in val]) |
|
208 elif isinstance(val, dict): |
|
209 for key, value in val.iteritems(): |
|
210 if isinstance(value, (list, tuple)): |
|
211 val[key] = ', '.join(sorted( str(v) for v in value)) |
|
212 val = str(val) |
|
213 |
177 elif isinstance(val, (list, tuple)): |
214 elif isinstance(val, (list, tuple)): |
|
215 val = sorted(val) |
178 val = ', '.join(str(v) for v in val) |
216 val = ', '.join(str(v) for v in val) |
179 elif val and isinstance(val, basestring): |
217 elif val and isinstance(val, basestring): |
180 val = _(val) |
218 val = _(val) |
181 else: |
219 else: |
182 val = str(val) |
220 val = str(val) |