99 self.w(self.req.__('%%d%sseconds' % space) % int(value.seconds)) |
97 self.w(self.req.__('%%d%sseconds' % space) % int(value.seconds)) |
100 return |
98 return |
101 self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime)) |
99 self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime)) |
102 |
100 |
103 |
101 |
104 PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity', |
|
105 'owned_by', 'created_by', |
|
106 'in_state', 'wf_info_for', 'require_permission', |
|
107 'from_entity', 'to_entity', |
|
108 'see_also']) |
|
109 |
|
110 class PrimaryView(EntityView): |
|
111 """the full view of an non final entity""" |
|
112 id = 'primary' |
|
113 title = _('primary') |
|
114 show_attr_label = True |
|
115 show_rel_label = True |
|
116 skip_none = True |
|
117 skip_attrs = ('eid', 'creation_date', 'modification_date') |
|
118 skip_rels = () |
|
119 main_related_section = True |
|
120 |
|
121 def html_headers(self): |
|
122 """return a list of html headers (eg something to be inserted between |
|
123 <head> and </head> of the returned page |
|
124 |
|
125 by default primary views are indexed |
|
126 """ |
|
127 return [] |
|
128 |
|
129 def cell_call(self, row, col): |
|
130 self.row = row |
|
131 # XXX move render_entity implementation here |
|
132 self.render_entity(self.complete_entity(row, col)) |
|
133 |
|
134 def render_entity(self, entity): |
|
135 """return html to display the given entity""" |
|
136 siderelations = [] |
|
137 self.render_entity_title(entity) |
|
138 self.render_entity_metadata(entity) |
|
139 # entity's attributes and relations, excluding meta data |
|
140 # if the entity isn't meta itself |
|
141 boxes = self._preinit_side_related(entity, siderelations) |
|
142 if boxes: |
|
143 self.w(u'<table width="100%"><tr><td width="75%">') |
|
144 self.w(u'<div>') |
|
145 self.w(u'<div class="mainInfo">') |
|
146 self.render_entity_attributes(entity, siderelations) |
|
147 self.w(u'</div>') |
|
148 self.content_navigation_components('navcontenttop') |
|
149 if self.main_related_section: |
|
150 self.render_entity_relations(entity, siderelations) |
|
151 self.w(u'</div>') |
|
152 if boxes: |
|
153 self.w(u'</td><td>') |
|
154 # side boxes |
|
155 self.w(u'<div class="primaryRight">') |
|
156 self.render_side_related(entity, siderelations) |
|
157 self.w(u'</div>') |
|
158 self.w(u'</td></tr></table>') |
|
159 self.content_navigation_components('navcontentbottom') |
|
160 |
|
161 |
|
162 def content_navigation_components(self, context): |
|
163 self.w(u'<div class="%s">' % context) |
|
164 for comp in self.vreg.possible_vobjects('contentnavigation', |
|
165 self.req, self.rset, row=self.row, |
|
166 view=self, context=context): |
|
167 try: |
|
168 comp.dispatch(w=self.w, row=self.row, view=self) |
|
169 except NotImplementedError: |
|
170 warn('component %s doesnt implement cell_call, please update' |
|
171 % comp.__class__, DeprecationWarning) |
|
172 comp.dispatch(w=self.w, view=self) |
|
173 self.w(u'</div>') |
|
174 |
|
175 def iter_attributes(self, entity): |
|
176 for rschema, targetschema in entity.e_schema.attribute_definitions(): |
|
177 if rschema.type in self.skip_attrs: |
|
178 continue |
|
179 yield rschema, targetschema |
|
180 |
|
181 def iter_relations(self, entity): |
|
182 skip = set(self.skip_rels) |
|
183 skip.update(PRIMARY_SKIP_RELS) |
|
184 for rschema, targetschemas, x in entity.e_schema.relation_definitions(): |
|
185 if rschema.type in skip: |
|
186 continue |
|
187 yield rschema, targetschemas, x |
|
188 |
|
189 def render_entity_title(self, entity): |
|
190 title = self.content_title(entity) # deprecate content_title? |
|
191 if title: |
|
192 self.w(u'<h1><span class="etype">%s</span> %s</h1>' |
|
193 % (entity.dc_type().capitalize(), title)) |
|
194 |
|
195 def content_title(self, entity): |
|
196 """default implementation return an empty string""" |
|
197 return u'' |
|
198 |
|
199 def render_entity_metadata(self, entity): |
|
200 entity.view('metadata', w=self.w) |
|
201 summary = self.summary(entity) # deprecate summary? |
|
202 if summary: |
|
203 self.w(u'<div class="summary">%s</div>' % summary) |
|
204 |
|
205 def summary(self, entity): |
|
206 """default implementation return an empty string""" |
|
207 return u'' |
|
208 |
|
209 def render_entity_attributes(self, entity, siderelations): |
|
210 for rschema, targetschema in self.iter_attributes(entity): |
|
211 attr = rschema.type |
|
212 if targetschema.type in ('Password', 'Bytes'): |
|
213 continue |
|
214 try: |
|
215 wdg = entity.get_widget(attr) |
|
216 except Exception, ex: |
|
217 value = entity.printable_value(attr, entity[attr], targetschema.type) |
|
218 else: |
|
219 value = wdg.render(entity) |
|
220 if self.skip_none and (value is None or value == ''): |
|
221 continue |
|
222 if rschema.meta: |
|
223 continue |
|
224 self._render_related_entities(entity, rschema, value) |
|
225 |
|
226 def _preinit_side_related(self, entity, siderelations): |
|
227 self._sideboxes = None |
|
228 self._related_entities = [] |
|
229 if hasattr(self, 'get_side_boxes_defs'): |
|
230 self._sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity) |
|
231 if rset] |
|
232 else: |
|
233 eschema = entity.e_schema |
|
234 maxrelated = self.req.property_value('navigation.related-limit') |
|
235 for rschema, targetschemas, x in self.iter_relations(entity): |
|
236 try: |
|
237 related = entity.related(rschema.type, x, limit=maxrelated+1) |
|
238 except Unauthorized: |
|
239 continue |
|
240 if not related: |
|
241 continue |
|
242 if self.is_side_related(rschema, eschema): |
|
243 siderelations.append((rschema, related, x)) |
|
244 continue |
|
245 self._related_entities.append((rschema, related, x)) |
|
246 self._boxes_in_context = list(self.vreg.possible_vobjects('boxes', self.req, self.rset, |
|
247 row=self.row, view=self, |
|
248 context='incontext')) |
|
249 return self._sideboxes or self._boxes_in_context or self._related_entities or siderelations |
|
250 |
|
251 def render_entity_relations(self, entity, siderelations): |
|
252 if self._related_entities: |
|
253 for rschema, related, x in self._related_entities: |
|
254 self._render_related_entities(entity, rschema, related, x) |
|
255 |
|
256 |
|
257 def render_side_related(self, entity, siderelations): |
|
258 """display side related relations: |
|
259 non-meta in a first step, meta in a second step |
|
260 """ |
|
261 if self._sideboxes: |
|
262 for label, rset in self._sideboxes: |
|
263 self.w(u'<div class="sideRelated">') |
|
264 self.wview('sidebox', rset, title=label) |
|
265 self.w(u'</div>') |
|
266 elif siderelations: |
|
267 self.w(u'<div class="sideRelated">') |
|
268 for relatedinfos in siderelations: |
|
269 # if not relatedinfos[0].meta: |
|
270 # continue |
|
271 self._render_related_entities(entity, *relatedinfos) |
|
272 self.w(u'</div>') |
|
273 |
|
274 if self._boxes_in_context: |
|
275 for box in self._boxes_in_context: |
|
276 try: |
|
277 box.dispatch(w=self.w, row=self.row) |
|
278 except NotImplementedError: |
|
279 # much probably a context insensitive box, which only implements |
|
280 # .call() and not cell_call() |
|
281 box.dispatch(w=self.w) |
|
282 |
|
283 def is_side_related(self, rschema, eschema): |
|
284 return rschema.meta and \ |
|
285 not rschema.schema_relation() == eschema.schema_entity() |
|
286 |
|
287 def _render_related_entities(self, entity, rschema, related, |
|
288 role='subject'): |
|
289 if rschema.is_final(): |
|
290 value = related |
|
291 show_label = self.show_attr_label |
|
292 else: |
|
293 if not related: |
|
294 return |
|
295 show_label = self.show_rel_label |
|
296 # if not too many entities, show them all in a list |
|
297 maxrelated = self.req.property_value('navigation.related-limit') |
|
298 if related.rowcount <= maxrelated: |
|
299 if related.rowcount == 1: |
|
300 value = self.view('incontext', related, row=0) |
|
301 elif 1 < related.rowcount <= 5: |
|
302 value = self.view('csv', related) |
|
303 else: |
|
304 value = '<div>' + self.view('simplelist', related) + '</div>' |
|
305 # else show links to display related entities |
|
306 else: |
|
307 rql = related.printable_rql() |
|
308 related.limit(maxrelated) |
|
309 value = '<div>' + self.view('simplelist', related) |
|
310 value += '[<a href="%s">%s</a>]' % (self.build_url(rql=rql), |
|
311 self.req._('see them all')) |
|
312 value += '</div>' |
|
313 label = display_name(self.req, rschema.type, role) |
|
314 self.field(label, value, show_label=show_label, tr=False) |
|
315 |
|
316 |
|
317 class SecondaryView(EntityView): |
102 class SecondaryView(EntityView): |
318 id = 'secondary' |
103 id = 'secondary' |
319 title = _('secondary') |
104 title = _('secondary') |
320 |
105 |
321 def cell_call(self, row, col): |
106 def cell_call(self, row, col): |