web/views/baseviews.py
branchtls-sprint
changeset 1491 742aff97dbf7
parent 1477 b056a49c16dc
child 1498 2c6eec0b46b9
equal deleted inserted replaced
1486:12bba5e13cf9 1491:742aff97dbf7
    12 """
    12 """
    13 #from __future__ import with_statement
    13 #from __future__ import with_statement
    14 
    14 
    15 __docformat__ = "restructuredtext en"
    15 __docformat__ = "restructuredtext en"
    16 
    16 
    17 from warnings import warn
       
    18 
       
    19 from rql import nodes
    17 from rql import nodes
    20 
    18 
    21 from logilab.mtconverter import TransformError, html_escape
    19 from logilab.mtconverter import TransformError, html_escape
    22 
    20 
    23 from cubicweb import Unauthorized, NoSelectableObject
    21 from cubicweb import NoSelectableObject
    24 from cubicweb.selectors import yes, empty_rset
    22 from cubicweb.selectors import yes, empty_rset
    25 from cubicweb.view import EntityView, AnyRsetView, View
    23 from cubicweb.view import EntityView, AnyRsetView, View
    26 from cubicweb.common.uilib import cut, printable_value
    24 from cubicweb.common.uilib import cut, printable_value
    27 
    25 
    28 _ = unicode
    26 _ = unicode
    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):
   584     from cubicweb.web.views.tableview import TableView
   369     from cubicweb.web.views.tableview import TableView
   585     TableView = class_moved(TableView)
   370     TableView = class_moved(TableView)
   586 except ImportError:
   371 except ImportError:
   587     pass # gae has no tableview module (yet)
   372     pass # gae has no tableview module (yet)
   588 
   373 
   589 from cubicweb.web.views import boxes, xmlrss
   374 from cubicweb.web.views import boxes, xmlrss, primary
       
   375 PrimaryView = class_moved(primary.PrimaryView)
   590 SideBoxView = class_moved(boxes.SideBoxView)
   376 SideBoxView = class_moved(boxes.SideBoxView)
   591 XmlView = class_moved(xmlrss.XmlView)
   377 XmlView = class_moved(xmlrss.XmlView)
   592 XmlItemView = class_moved(xmlrss.XmlItemView)
   378 XmlItemView = class_moved(xmlrss.XmlItemView)
   593 XmlRsetView = class_moved(xmlrss.XmlRsetView)
   379 XmlRsetView = class_moved(xmlrss.XmlRsetView)
   594 RssView = class_moved(xmlrss.RssView)
   380 RssView = class_moved(xmlrss.RssView)