--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/primary.py Tue Apr 28 10:10:04 2009 +0200
@@ -0,0 +1,226 @@
+"""The default primary view
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+
+from warnings import warn
+
+from cubicweb import Unauthorized
+from cubicweb.view import EntityView
+
+_ = unicode
+
+PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity',
+ 'owned_by', 'created_by',
+ 'in_state', 'wf_info_for', 'require_permission',
+ 'from_entity', 'to_entity',
+ 'see_also'])
+
+class PrimaryView(EntityView):
+ """the full view of an non final entity"""
+ id = 'primary'
+ title = _('primary')
+ show_attr_label = True
+ show_rel_label = True
+ skip_none = True
+ skip_attrs = ('eid', 'creation_date', 'modification_date')
+ skip_rels = ()
+ main_related_section = True
+
+ def html_headers(self):
+ """return a list of html headers (eg something to be inserted between
+ <head> and </head> of the returned page
+
+ by default primary views are indexed
+ """
+ return []
+
+ def cell_call(self, row, col):
+ self.row = row
+ # XXX move render_entity implementation here
+ self.render_entity(self.complete_entity(row, col))
+
+ def render_entity(self, entity):
+ """return html to display the given entity"""
+ siderelations = []
+ self.render_entity_title(entity)
+ self.render_entity_metadata(entity)
+ # entity's attributes and relations, excluding meta data
+ # if the entity isn't meta itself
+ boxes = self._preinit_side_related(entity, siderelations)
+ if boxes:
+ self.w(u'<table width="100%"><tr><td width="75%">')
+ self.w(u'<div>')
+ self.w(u'<div class="mainInfo">')
+ self.render_entity_attributes(entity, siderelations)
+ self.w(u'</div>')
+ self.content_navigation_components('navcontenttop')
+ if self.main_related_section:
+ self.render_entity_relations(entity, siderelations)
+ self.w(u'</div>')
+ if boxes:
+ self.w(u'</td><td>')
+ # side boxes
+ self.w(u'<div class="primaryRight">')
+ self.render_side_related(entity, siderelations)
+ self.w(u'</div>')
+ self.w(u'</td></tr></table>')
+ self.content_navigation_components('navcontentbottom')
+
+
+ def content_navigation_components(self, context):
+ self.w(u'<div class="%s">' % context)
+ for comp in self.vreg.possible_vobjects('contentnavigation',
+ self.req, self.rset, row=self.row,
+ view=self, context=context):
+ try:
+ comp.dispatch(w=self.w, row=self.row, view=self)
+ except NotImplementedError:
+ warn('component %s doesnt implement cell_call, please update'
+ % comp.__class__, DeprecationWarning)
+ comp.dispatch(w=self.w, view=self)
+ self.w(u'</div>')
+
+ def iter_attributes(self, entity):
+ for rschema, targetschema in entity.e_schema.attribute_definitions():
+ if rschema.type in self.skip_attrs:
+ continue
+ yield rschema, targetschema
+
+ def iter_relations(self, entity):
+ skip = set(self.skip_rels)
+ skip.update(PRIMARY_SKIP_RELS)
+ for rschema, targetschemas, x in entity.e_schema.relation_definitions():
+ if rschema.type in skip:
+ continue
+ yield rschema, targetschemas, x
+
+ def render_entity_title(self, entity):
+ title = self.content_title(entity) # deprecate content_title?
+ if title:
+ self.w(u'<h1><span class="etype">%s</span> %s</h1>'
+ % (entity.dc_type().capitalize(), title))
+
+ def content_title(self, entity):
+ """default implementation return an empty string"""
+ return u''
+
+ def render_entity_metadata(self, entity):
+ entity.view('metadata', w=self.w)
+ summary = self.summary(entity) # deprecate summary?
+ if summary:
+ self.w(u'<div class="summary">%s</div>' % summary)
+
+ def summary(self, entity):
+ """default implementation return an empty string"""
+ return u''
+
+ def render_entity_attributes(self, entity, siderelations):
+ for rschema, targetschema in self.iter_attributes(entity):
+ attr = rschema.type
+ if targetschema.type in ('Password', 'Bytes'):
+ continue
+ try:
+ wdg = entity.get_widget(attr)
+ except Exception, ex:
+ value = entity.printable_value(attr, entity[attr], targetschema.type)
+ else:
+ value = wdg.render(entity)
+ if self.skip_none and (value is None or value == ''):
+ continue
+ if rschema.meta:
+ continue
+ self._render_related_entities(entity, rschema, value)
+
+ def _preinit_side_related(self, entity, siderelations):
+ self._sideboxes = None
+ self._related_entities = []
+ if hasattr(self, 'get_side_boxes_defs'):
+ self._sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity)
+ if rset]
+ else:
+ eschema = entity.e_schema
+ maxrelated = self.req.property_value('navigation.related-limit')
+ for rschema, targetschemas, x in self.iter_relations(entity):
+ try:
+ related = entity.related(rschema.type, x, limit=maxrelated+1)
+ except Unauthorized:
+ continue
+ if not related:
+ continue
+ if self.is_side_related(rschema, eschema):
+ siderelations.append((rschema, related, x))
+ continue
+ self._related_entities.append((rschema, related, x))
+ self._boxes_in_context = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ row=self.row, view=self,
+ context='incontext'))
+ return self._sideboxes or self._boxes_in_context or self._related_entities or siderelations
+
+ def render_entity_relations(self, entity, siderelations):
+ if self._related_entities:
+ for rschema, related, x in self._related_entities:
+ self._render_related_entities(entity, rschema, related, x)
+
+
+ def render_side_related(self, entity, siderelations):
+ """display side related relations:
+ non-meta in a first step, meta in a second step
+ """
+ if self._sideboxes:
+ for label, rset in self._sideboxes:
+ self.w(u'<div class="sideRelated">')
+ self.wview('sidebox', rset, title=label)
+ self.w(u'</div>')
+ elif siderelations:
+ self.w(u'<div class="sideRelated">')
+ for relatedinfos in siderelations:
+ # if not relatedinfos[0].meta:
+ # continue
+ self._render_related_entities(entity, *relatedinfos)
+ self.w(u'</div>')
+
+ if self._boxes_in_context:
+ for box in self._boxes_in_context:
+ try:
+ box.dispatch(w=self.w, row=self.row)
+ except NotImplementedError:
+ # much probably a context insensitive box, which only implements
+ # .call() and not cell_call()
+ box.dispatch(w=self.w)
+
+ def is_side_related(self, rschema, eschema):
+ return rschema.meta and \
+ not rschema.schema_relation() == eschema.schema_entity()
+
+ def _render_related_entities(self, entity, rschema, related,
+ role='subject'):
+ if rschema.is_final():
+ value = related
+ show_label = self.show_attr_label
+ else:
+ if not related:
+ return
+ show_label = self.show_rel_label
+ # if not too many entities, show them all in a list
+ maxrelated = self.req.property_value('navigation.related-limit')
+ if related.rowcount <= maxrelated:
+ if related.rowcount == 1:
+ value = self.view('incontext', related, row=0)
+ elif 1 < related.rowcount <= 5:
+ value = self.view('csv', related)
+ else:
+ value = '<div>' + self.view('simplelist', related) + '</div>'
+ # else show links to display related entities
+ else:
+ rql = related.printable_rql()
+ related.limit(maxrelated)
+ value = '<div>' + self.view('simplelist', related)
+ value += '[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
+ self.req._('see them all'))
+ value += '</div>'
+ label = display_name(self.req, rschema.type, role)
+ self.field(label, value, show_label=show_label, tr=False)
+