web/views/primary.py
branchtls-sprint
changeset 1491 742aff97dbf7
child 1516 288d55a7c5e2
equal deleted inserted replaced
1486:12bba5e13cf9 1491:742aff97dbf7
       
     1 """The default primary view
       
     2 
       
     3 :organization: Logilab
       
     4 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     6 """
       
     7 
       
     8 from warnings import warn
       
     9 
       
    10 from cubicweb import Unauthorized
       
    11 from cubicweb.view import EntityView
       
    12 
       
    13 _ = unicode
       
    14 
       
    15 PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity',
       
    16                          'owned_by', 'created_by',
       
    17                          'in_state', 'wf_info_for', 'require_permission',
       
    18                          'from_entity', 'to_entity',
       
    19                          'see_also'])
       
    20 
       
    21 class PrimaryView(EntityView):
       
    22     """the full view of an non final entity"""
       
    23     id = 'primary'
       
    24     title = _('primary')
       
    25     show_attr_label = True
       
    26     show_rel_label = True
       
    27     skip_none = True
       
    28     skip_attrs = ('eid', 'creation_date', 'modification_date')
       
    29     skip_rels = ()
       
    30     main_related_section = True
       
    31 
       
    32     def html_headers(self):
       
    33         """return a list of html headers (eg something to be inserted between
       
    34         <head> and </head> of the returned page
       
    35 
       
    36         by default primary views are indexed
       
    37         """
       
    38         return []
       
    39 
       
    40     def cell_call(self, row, col):
       
    41         self.row = row
       
    42         # XXX move render_entity implementation here
       
    43         self.render_entity(self.complete_entity(row, col))
       
    44 
       
    45     def render_entity(self, entity):
       
    46         """return html to display the given entity"""
       
    47         siderelations = []
       
    48         self.render_entity_title(entity)
       
    49         self.render_entity_metadata(entity)
       
    50         # entity's attributes and relations, excluding meta data
       
    51         # if the entity isn't meta itself
       
    52         boxes = self._preinit_side_related(entity, siderelations)
       
    53         if boxes:
       
    54             self.w(u'<table width="100%"><tr><td width="75%">')
       
    55         self.w(u'<div>')
       
    56         self.w(u'<div class="mainInfo">')
       
    57         self.render_entity_attributes(entity, siderelations)
       
    58         self.w(u'</div>')
       
    59         self.content_navigation_components('navcontenttop')
       
    60         if self.main_related_section:
       
    61             self.render_entity_relations(entity, siderelations)
       
    62         self.w(u'</div>')
       
    63         if boxes:
       
    64             self.w(u'</td><td>')
       
    65             # side boxes
       
    66             self.w(u'<div class="primaryRight">')
       
    67             self.render_side_related(entity, siderelations)
       
    68             self.w(u'</div>')
       
    69             self.w(u'</td></tr></table>')
       
    70         self.content_navigation_components('navcontentbottom')
       
    71 
       
    72 
       
    73     def content_navigation_components(self, context):
       
    74         self.w(u'<div class="%s">' % context)
       
    75         for comp in self.vreg.possible_vobjects('contentnavigation',
       
    76                                                 self.req, self.rset, row=self.row,
       
    77                                                 view=self, context=context):
       
    78             try:
       
    79                 comp.dispatch(w=self.w, row=self.row, view=self)
       
    80             except NotImplementedError:
       
    81                 warn('component %s doesnt implement cell_call, please update'
       
    82                      % comp.__class__, DeprecationWarning)
       
    83                 comp.dispatch(w=self.w, view=self)
       
    84         self.w(u'</div>')
       
    85 
       
    86     def iter_attributes(self, entity):
       
    87         for rschema, targetschema in entity.e_schema.attribute_definitions():
       
    88             if rschema.type in self.skip_attrs:
       
    89                 continue
       
    90             yield rschema, targetschema
       
    91 
       
    92     def iter_relations(self, entity):
       
    93         skip = set(self.skip_rels)
       
    94         skip.update(PRIMARY_SKIP_RELS)
       
    95         for rschema, targetschemas, x in entity.e_schema.relation_definitions():
       
    96             if rschema.type in skip:
       
    97                 continue
       
    98             yield rschema, targetschemas, x
       
    99 
       
   100     def render_entity_title(self, entity):
       
   101         title = self.content_title(entity) # deprecate content_title?
       
   102         if title:
       
   103             self.w(u'<h1><span class="etype">%s</span> %s</h1>'
       
   104                    % (entity.dc_type().capitalize(), title))
       
   105 
       
   106     def content_title(self, entity):
       
   107         """default implementation return an empty string"""
       
   108         return u''
       
   109 
       
   110     def render_entity_metadata(self, entity):
       
   111         entity.view('metadata', w=self.w)
       
   112         summary = self.summary(entity) # deprecate summary?
       
   113         if summary:
       
   114             self.w(u'<div class="summary">%s</div>' % summary)
       
   115 
       
   116     def summary(self, entity):
       
   117         """default implementation return an empty string"""
       
   118         return u''
       
   119 
       
   120     def render_entity_attributes(self, entity, siderelations):
       
   121         for rschema, targetschema in self.iter_attributes(entity):
       
   122             attr = rschema.type
       
   123             if targetschema.type in ('Password', 'Bytes'):
       
   124                 continue
       
   125             try:
       
   126                 wdg = entity.get_widget(attr)
       
   127             except Exception, ex:
       
   128                 value = entity.printable_value(attr, entity[attr], targetschema.type)
       
   129             else:
       
   130                 value = wdg.render(entity)
       
   131             if self.skip_none and (value is None or value == ''):
       
   132                 continue
       
   133             if rschema.meta:
       
   134                 continue
       
   135             self._render_related_entities(entity, rschema, value)
       
   136 
       
   137     def _preinit_side_related(self, entity, siderelations):
       
   138         self._sideboxes = None
       
   139         self._related_entities = []
       
   140         if hasattr(self, 'get_side_boxes_defs'):
       
   141             self._sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity)
       
   142                                if rset]
       
   143         else:
       
   144             eschema = entity.e_schema
       
   145             maxrelated = self.req.property_value('navigation.related-limit')
       
   146             for rschema, targetschemas, x in self.iter_relations(entity):
       
   147                 try:
       
   148                     related = entity.related(rschema.type, x, limit=maxrelated+1)
       
   149                 except Unauthorized:
       
   150                     continue
       
   151                 if not related:
       
   152                     continue
       
   153                 if self.is_side_related(rschema, eschema):
       
   154                     siderelations.append((rschema, related, x))
       
   155                     continue
       
   156                 self._related_entities.append((rschema, related, x))
       
   157         self._boxes_in_context = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
       
   158                                                  row=self.row, view=self,
       
   159                                                  context='incontext'))
       
   160         return self._sideboxes or self._boxes_in_context or self._related_entities or siderelations
       
   161 
       
   162     def render_entity_relations(self, entity, siderelations):
       
   163         if self._related_entities:
       
   164             for rschema, related, x in self._related_entities:
       
   165                 self._render_related_entities(entity, rschema, related, x)
       
   166 
       
   167 
       
   168     def render_side_related(self, entity, siderelations):
       
   169         """display side related relations:
       
   170         non-meta in a first step, meta in a second step
       
   171         """
       
   172         if self._sideboxes:
       
   173             for label, rset in self._sideboxes:
       
   174                 self.w(u'<div class="sideRelated">')
       
   175                 self.wview('sidebox', rset, title=label)
       
   176                 self.w(u'</div>')
       
   177         elif siderelations:
       
   178             self.w(u'<div class="sideRelated">')
       
   179             for relatedinfos in siderelations:
       
   180                 # if not relatedinfos[0].meta:
       
   181                 #    continue
       
   182                 self._render_related_entities(entity, *relatedinfos)
       
   183             self.w(u'</div>')
       
   184 
       
   185         if self._boxes_in_context:
       
   186             for box in self._boxes_in_context:
       
   187                 try:
       
   188                     box.dispatch(w=self.w, row=self.row)
       
   189                 except NotImplementedError:
       
   190                     # much probably a context insensitive box, which only implements
       
   191                     # .call() and not cell_call()
       
   192                     box.dispatch(w=self.w)
       
   193 
       
   194     def is_side_related(self, rschema, eschema):
       
   195         return rschema.meta and \
       
   196                not rschema.schema_relation() == eschema.schema_entity()
       
   197 
       
   198     def _render_related_entities(self, entity, rschema, related,
       
   199                                  role='subject'):
       
   200         if rschema.is_final():
       
   201             value = related
       
   202             show_label = self.show_attr_label
       
   203         else:
       
   204             if not related:
       
   205                 return
       
   206             show_label = self.show_rel_label
       
   207             # if not too many entities, show them all in a list
       
   208             maxrelated = self.req.property_value('navigation.related-limit')
       
   209             if related.rowcount <= maxrelated:
       
   210                 if related.rowcount == 1:
       
   211                     value = self.view('incontext', related, row=0)
       
   212                 elif 1 < related.rowcount <= 5:
       
   213                     value = self.view('csv', related)
       
   214                 else:
       
   215                     value = '<div>' + self.view('simplelist', related) + '</div>'
       
   216             # else show links to display related entities
       
   217             else:
       
   218                 rql = related.printable_rql()
       
   219                 related.limit(maxrelated)
       
   220                 value = '<div>' + self.view('simplelist', related)
       
   221                 value += '[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
       
   222                                                     self.req._('see them all'))
       
   223                 value +=  '</div>'
       
   224         label = display_name(self.req, rschema.type, role)
       
   225         self.field(label, value, show_label=show_label, tr=False)
       
   226