--- a/web/views/primary.py Thu Apr 30 00:41:10 2009 +0200
+++ b/web/views/primary.py Thu Apr 30 00:41:52 2009 +0200
@@ -4,19 +4,18 @@
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
+__docformat__ = "restructuredtext en"
from warnings import warn
+from logilab.mtconverter import html_escape
+
from cubicweb import Unauthorized
from cubicweb.view import EntityView
+from cubicweb.web.uicfg import rdisplay
_ = 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"""
@@ -25,10 +24,44 @@
show_attr_label = True
show_rel_label = True
skip_none = True
- skip_attrs = ('eid', 'creation_date', 'modification_date')
- skip_rels = ()
+ rdisplay = rdisplay
main_related_section = True
+ @classmethod
+ def vreg_initialization_completed(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]
+ composed = rschema.rproperty(X, Y, 'composite') == 'object'
+ else:
+ X, Y = tschema, eschema
+ card = rschema.rproperty(X, Y, 'cardinality')[1]
+ composed = rschema.rproperty(X, Y, 'composite') == 'subject'
+ displayinfo = cls.rdisplay.get(rschema, role, X, Y)
+ if displayinfo is None:
+ if rschema.is_final():
+ if rschema.meta or tschema.type in ('Password', 'Bytes'):
+ where = None
+ else:
+ where = 'attributes'
+ elif card in '1+':
+ where = 'attributes'
+ elif composed:
+ where = 'relations'
+ else:
+ where = 'sideboxes'
+ displayinfo = {'where': where,
+ 'order': cls.rdisplay.get_timestamp()}
+ cls.rdisplay.tag_relation(displayinfo, (X, rschema, Y),
+ role)
+ displayinfo.setdefault('label', '%s_%s' % (rschema, role))
+
def html_headers(self):
"""return a list of html headers (eg something to be inserted between
<head> and </head> of the returned page
@@ -41,6 +74,7 @@
self.row = row
# XXX move render_entity implementation here
self.render_entity(self.complete_entity(row, col))
+ self.maxrelated = self.req.property_value('navigation.related-limit')
def render_entity(self, entity):
"""return html to display the given entity"""
@@ -48,8 +82,8 @@
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)
- if boxes:
+ boxes = self._prepare_side_boxes(entity)
+ if boxes or hasattr(self, 'render_side_related'):
self.w(u'<table width="100%"><tr><td width="75%">')
self.w(u'<div>')
self.w(u'<div class="mainInfo">')
@@ -69,16 +103,14 @@
'deprecated')
self.render_entity_relations(entity, [])
self.w(u'</div>')
- if boxes:
+ if boxes or hasattr(self, 'render_side_related'):
self.w(u'</td><td>')
# side boxes
self.w(u'<div class="primaryRight">')
- try:
- self.render_side_related(entity)
- except TypeError: # XXX bw compat
- warn('siderelations argument of render_entity_relations is '
- 'deprecated')
- self.render_entity_relations(entity, [])
+ if hasattr(self, 'render_side_related'):
+ warn('render_side_related is deprecated')
+ self.render_side_related(entity, [])
+ self.render_side_boxes(boxes)
self.w(u'</div>')
self.w(u'</td></tr></table>')
self.content_navigation_components('navcontentbottom')
@@ -97,29 +129,16 @@
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''
+ """default implementation return dc_title"""
+ return html_escape(entity.dc_title())
def render_entity_metadata(self, entity):
entity.view('metadata', w=self.w)
@@ -132,67 +151,39 @@
return u''
def render_entity_attributes(self, entity, siderelations=None):
- 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)
+ for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'attributes'):
+ vid = displayinfo.get('vid', 'reledit')
+ if rschema.is_final():
+ value = entity.view('reledit', rtype=rschema.type)
else:
- value = wdg.render(entity)
+ vid = displayinfo.get('vid', 'reledit')
+ rset = self._relation_rset(entity, rschema, role, displayinfo)
+ if rset:
+ value = self.view(rset, vid)
+ else:
+ value = None
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):
- self._sideboxes = []
- if hasattr(self, 'get_side_boxes_defs'):
- self._sideboxes = [(label, rset, 'sidebox') 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, role in self.iter_relations(entity):
- if self.is_side_related(rschema, eschema):
- try:
- related = entity.related(rschema.type, role, limit=maxrelated+1)
- except Unauthorized:
- continue
- if not related:
- continue
- label = display_name(self.req, rschema.type, role)
- self._sideboxes.append((label, related, 'autolimited'))
- self._contextboxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
- row=self.row, view=self,
- context='incontext'))
- return self._sideboxes or self._contextboxes
+ self._render_attribute(rschema, value)
def render_entity_relations(self, entity, siderelations=None):
- eschema = entity.e_schema
- for rschema, targetschemas, x in self.iter_relations(entity):
- if not self.is_side_related(rschema, eschema):
- try:
- related = entity.related(rschema.type, x, limit=maxrelated+1)
- except Unauthorized:
- continue
- self._render_related_entities(entity, rschema, related, x)
+ for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'relations'):
+ rset = self._relation_rset(entity, rschema, role, displayinfo)
+ if rset:
+ self._render_relation(rset, displayinfo, 'autolimited',
+ self.show_rel_label)
-
- def render_side_related(self, entity, siderelations=None):
+ def render_side_boxes(self, boxes):
"""display side related relations:
non-meta in a first step, meta in a second step
"""
- if self._sideboxes:
- for label, rset, vid in self._sideboxes:
+ for box in boxes:
+ if isinstance(box, tuple):
+ label, rset, vid, _ = box
self.w(u'<div class="sideRelated">')
self.wview(vid, rset, title=label)
self.w(u'</div>')
- if self._contextboxes:
- for box in self._contextboxes:
+ else:
try:
box.dispatch(w=self.w, row=self.row)
except NotImplementedError:
@@ -200,28 +191,73 @@
# .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 _prepare_side_boxes(self, entity):
+ sideboxes = []
+ for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'sideboxes'):
+ rset = self._relation_rset(entity, rschema, role, displayinfo)
+ if not rset:
+ continue
+ label = display_name(self.req, rschema.type, role)
+ vid = displayinfo.get('vid', 'autolimited')
+ sideboxes.append((label, rset, vid, displayinfo.get('order')))
+ sideboxes = sorted(sideboxes, key=lambda x: x[-1])
+ sideboxes += list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ row=self.row, view=self,
+ context='incontext'))
+ return sideboxes
- def _render_related_entities(self, entity, rschema, related,
- role='subject'):
+ def _iter_display(self, entity, where):
+ eschema = entity.e_schema
+ for rschema, tschemas, role in eschema.relation_definitions(True):
+ matchtschemas = []
+ for tschema in tschemas:
+ displayinfo = self.rdisplay.etype_get(eschema, rschema, role,
+ tschema)
+ assert displayinfo is not None, (str(rschema), role,
+ str(eschema), str(tschema))
+ if displayinfo.get('where') == where:
+ matchtschemas.append(tschema)
+ if matchtschemas:
+ # XXX pick the latest displayinfo
+ yield rschema, matchtschemas, role, displayinfo
+
+ def _relation_rset(self, entity, rschema, role, displayinfo):
+ try:
+ if displayinfo.get('limit'):
+ rset = entity.related(rschema.type, role,
+ limit=self.maxrelated+1)
+ else:
+ rset = entity.related(rschema.type, role)
+ except Unauthorized:
+ return
+ if 'filter' in displayinfo:
+ rset = displayinfo['filter'](rset)
+ return rset
+
+ def _render_relation(self, rset, displayinfo, defaultvid, showlabel):
+ self.w('<div class="section">')
+ if showlabel:
+ label = self.req._(displayinfo['label'])
+ self.w('<h4>%s</h4>' % label)
+ self.wview(displayinfo.get('vid', defaultvid), rset)
+ self.w('</div>')
+
+ def _render_attribute(self, rschema, value, role='subject'):
if rschema.is_final():
- value = related
show_label = self.show_attr_label
else:
- if not related:
- return
- value = self.view('autolimited', related)
+ show_label = self.show_rel_label
label = display_name(self.req, rschema.type, role)
self.field(label, value, show_label=show_label, tr=False)
class RelatedView(EntityView):
id = 'autolimited'
- def call(self):
+ def call(self, title=None, **kwargs):
# if not too many entities, show them all in a list
maxrelated = self.req.property_value('navigation.related-limit')
+ if title:
+ self.w(u'<div class="title"><span>%s</span></div>' % title)
if self.rset.rowcount <= maxrelated:
if self.rset.rowcount == 1:
self.wview('incontext', self.rset, row=0)
@@ -234,7 +270,7 @@
# else show links to display related entities
else:
rql = self.rset.printable_rql()
- self.rset.limit(maxself.rset)
+ self.rset.limit(maxrelated)
self.w(u'<div>')
self.wview('simplelist', self.rset)
self.w(u'[<a href="%s">%s</a>]' % (self.build_url(rql=rql),