web/views/baseviews.py
branchstable
changeset 7836 0ada13ce2e16
parent 7835 c071e0b70bf5
child 7840 d6733436b0dd
--- a/web/views/baseviews.py	Thu Sep 22 19:02:29 2011 +0200
+++ b/web/views/baseviews.py	Thu Sep 22 19:02:36 2011 +0200
@@ -15,12 +15,64 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""Set of HTML generic base views:
+"""
+HTML views
+~~~~~~~~~~
+
+Special views
+`````````````
+
+.. autoclass:: NullView
+.. autoclass:: NoResultView
+.. autoclass:: FinalView
+
+
+Base entity views
+`````````````````
+
+.. autoclass:: InContextView
+.. autoclass:: OutOfContextView
+.. autoclass:: OneLineView
 
-* noresult, final
-* primary, sidebox
-* oneline, incontext, outofcontext, text
-* list
+Those are used to display a link to an entity, whose label depends on the entity
+having to be displayed in or out of context (of another entity): some entities
+make sense in the context of another entity. For instance, the `Version` of a
+`Project` in forge. So one may expect that 'incontext' will be called when
+display a version from within the context of a project, while 'outofcontext"'
+will be called in other cases. In our example, the 'incontext' view of the
+version would be something like '0.1.2', while the 'outofcontext' view would
+include the project name, e.g. 'baz 0.1.2' (since only a version number without
+the associated project doesn't make sense if you don't know yet that you're
+talking about the famous 'baz' project. |cubicweb| tries to make guess and call
+'incontext'/'outofcontext' nicely. When it can't know, the 'oneline' view should
+be used.
+
+
+List entity views
+`````````````````
+
+.. autoclass:: ListView
+.. autoclass:: SimpleListView
+.. autoclass:: SameETypeListView
+.. autoclass:: CSVView
+
+Those list views can be given a 'subvid' arguments, telling the view to use of
+each item in the list. When not specified, the value of the 'redirect_vid'
+attribute of :class:`ListItemView` (for 'listview') or of
+:class:`SimpleListView` will be used. This default to 'outofcontext' for 'list'
+/ 'incontext' for 'simplelist'
+
+
+Text entity views
+~~~~~~~~~~~~~~~~~
+
+Basic HTML view have some variants to be used when generating raw text, not HTML
+(for notifications for instance). Also, as explained above, some of the HTML
+views use those text views as a basis.
+
+.. autoclass:: TextView
+.. autoclass:: InContextTextView
+.. autoclass:: OutOfContextView
 """
 
 __docformat__ = "restructuredtext en"
@@ -42,7 +94,12 @@
 
 
 class NullView(AnyRsetView):
-    """default view when no result has been found"""
+    """:__regid__: *null*
+
+    This view is the default view used when nothing needs to be rendered. It is
+    always applicable and is usually used as fallback view when calling
+    :meth:`_cw.view` to display nothing if the result set is empty.
+    """
     __regid__ = 'null'
     __select__ = yes()
     def call(self, **kwargs):
@@ -51,9 +108,16 @@
 
 
 class NoResultView(View):
-    """default view when no result has been found"""
+    """:__regid__: *noresult*
+
+    This view is the default view to be used when no result has been found
+    (i.e. empty result set).
+
+    It's usually used as fallback view when calling :meth:`_cw.view` to display
+    "no results" if the result set is empty.
+    """
+    __regid__ = 'noresult'
     __select__ = empty_rset()
-    __regid__ = 'noresult'
 
     def call(self, **kwargs):
         self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
@@ -61,8 +125,11 @@
 
 
 class FinalView(AnyRsetView):
-    """display values without any transformation (i.e. get a number for
-    entities)
+    """:__regid__: *final*
+
+    Display the value of a result set cell with minimal transformations
+    (i.e. you'll get a number for entities). It is applicable on any result set,
+    though usually dedicated for cells containing an attribute's value.
     """
     __regid__ = 'final'
     # record generated i18n catalog messages
@@ -126,21 +193,51 @@
         self.wdata(printable_value(self._cw, etype, value, props))
 
 
-# XXX deprecated
-class SecondaryView(EntityView):
-    __regid__ = 'secondary'
-    title = _('secondary')
+class InContextView(EntityView):
+    """:__regid__: *incontext*
+
+    This view is used whenthe entity should be considered as displayed in its
+    context. By default it produces the result of `textincontext` wrapped in a
+    link leading to the primary view of the entity.
+    """
+    __regid__ = 'incontext'
+
+    def cell_call(self, row, col):
+        entity = self.cw_rset.get_entity(row, col)
+        desc = cut(entity.dc_description(), 50)
+        self.w(u'<a href="%s" title="%s">' % (
+            xml_escape(entity.absolute_url()), xml_escape(desc)))
+        self.w(xml_escape(self._cw.view('textincontext', self.cw_rset,
+                                        row=row, col=col)))
+        self.w(u'</a>')
 
-    def cell_call(self, row, col, **kwargs):
-        """the secondary view for an entity
-        secondary = icon + view(oneline)
-        """
+
+class OutOfContextView(EntityView):
+    """:__regid__: *outofcontext*
+
+    This view is used whenthe entity should be considered as displayed out of
+    its context. By default it produces the result of `textoutofcontext` wrapped
+    in a link leading to the primary view of the entity.
+    """
+    __regid__ = 'outofcontext'
+
+    def cell_call(self, row, col):
         entity = self.cw_rset.get_entity(row, col)
-        self.w(u'&#160;')
-        self.wview('oneline', self.cw_rset, row=row, col=col)
+        desc = cut(entity.dc_description(), 50)
+        self.w(u'<a href="%s" title="%s">' % (
+            xml_escape(entity.absolute_url()), xml_escape(desc)))
+        self.w(xml_escape(self._cw.view('textoutofcontext', self.cw_rset,
+                                        row=row, col=col)))
+        self.w(u'</a>')
 
 
 class OneLineView(EntityView):
+    """:__regid__: *oneline*
+
+    This view is used when we can't tell if the entity should be considered as
+    displayed in or out of context. By default it produces the result of the
+    `text` view in a link leading to the primary view of the entity.
+    """
     __regid__ = 'oneline'
     title = _('oneline')
 
@@ -153,18 +250,25 @@
         self.w(u'</a>')
 
 
+# text views ###################################################################
+
 class TextView(EntityView):
-    """the simplest text view for an entity"""
+    """:__regid__: *text*
+
+    This is the simplest text view for an entity. By default it returns the
+    result of the entity's `dc_title()` method, which is cut to fit the
+    `navigation.short-line-size` property if necessary.
+    """
     __regid__ = 'text'
     title = _('text')
     content_type = 'text/plain'
 
     def call(self, **kwargs):
-        """the view is called for an entire result set, by default loop
-        other rows of the result set and call the same view on the
-        particular row
+        """The view is called for an entire result set, by default loop other
+        rows of the result set and call the same view on the particular row.
 
-        Views applicable on None result sets have to override this method
+        Subclasses views that are applicable on None result sets will have to
+        override this method.
         """
         rset = self.cw_rset
         if rset is None:
@@ -180,40 +284,14 @@
                    self._cw.property_value('navigation.short-line-size')))
 
 
-class MetaDataView(EntityView):
-    """paragraph view of some metadata"""
-    __regid__ = 'metadata'
-    show_eid = True
+class InContextTextView(TextView):
+    """:__regid__: *textincontext*
 
-    def cell_call(self, row, col):
-        _ = self._cw._
-        entity = self.cw_rset.get_entity(row, col)
-        self.w(u'<div>')
-        if self.show_eid:
-            self.w(u'%s #%s - ' % (entity.dc_type(), entity.eid))
-        if entity.modification_date != entity.creation_date:
-            self.w(u'<span>%s</span> ' % _('latest update on'))
-            self.w(u'<span class="value">%s</span>, '
-                   % self._cw.format_date(entity.modification_date))
-        # entities from external source may not have a creation date (eg ldap)
-        if entity.creation_date:
-            self.w(u'<span>%s</span> ' % _('created on'))
-            self.w(u'<span class="value">%s</span>'
-                   % self._cw.format_date(entity.creation_date))
-        if entity.creator:
-            if entity.creation_date:
-                self.w(u' <span>%s</span> ' % _('by'))
-            else:
-                self.w(u' <span>%s</span> ' % _('created_by'))
-            self.w(u'<span class="value">%s</span>' % entity.creator.name())
-        meta = entity.cw_metainformation()
-        if meta['source']['uri'] != 'system':
-            self.w(u' (<span>%s</span>' % _('cw_source'))
-            self.w(u' <span class="value">%s</span>)' % meta['source']['uri'])
-        self.w(u'</div>')
-
-
-class InContextTextView(TextView):
+    Similar to the `text` view, but called when an entity is considered in
+    context (see description of incontext HTML view for more information on
+    this). By default it displays what's returned by the `dc_title()` method of
+    the entity.
+    """
     __regid__ = 'textincontext'
     title = None # not listed as a possible view
     def cell_call(self, row, col):
@@ -222,6 +300,13 @@
 
 
 class OutOfContextTextView(InContextTextView):
+    """:__regid__: *textoutofcontext*
+
+    Similar to the `text` view, but called when an entity is considered out of
+    context (see description of outofcontext HTML view for more information on
+    this). By default it displays what's returned by the `dc_long_title()`
+    method of the entity.
+    """
     __regid__ = 'textoutofcontext'
 
     def cell_call(self, row, col):
@@ -229,35 +314,26 @@
         self.w(entity.dc_long_title())
 
 
-class InContextView(EntityView):
-    __regid__ = 'incontext'
-
-    def cell_call(self, row, col):
-        entity = self.cw_rset.get_entity(row, col)
-        desc = cut(entity.dc_description(), 50)
-        self.w(u'<a href="%s" title="%s">' % (
-            xml_escape(entity.absolute_url()), xml_escape(desc)))
-        self.w(xml_escape(self._cw.view('textincontext', self.cw_rset,
-                                        row=row, col=col)))
-        self.w(u'</a>')
-
-
-class OutOfContextView(EntityView):
-    __regid__ = 'outofcontext'
-
-    def cell_call(self, row, col):
-        entity = self.cw_rset.get_entity(row, col)
-        desc = cut(entity.dc_description(), 50)
-        self.w(u'<a href="%s" title="%s">' % (
-            xml_escape(entity.absolute_url()), xml_escape(desc)))
-        self.w(xml_escape(self._cw.view('textoutofcontext', self.cw_rset,
-                                        row=row, col=col)))
-        self.w(u'</a>')
-
-
 # list views ##################################################################
 
 class ListView(EntityView):
+    """:__regid__: *list*
+
+    This view displays a list of entities by creating a HTML list (`<ul>`) and
+    call the view `listitem` for each entity of the result set. The 'list' view
+    will generate HTML like:
+
+    .. sourcecode:: html
+
+      <ul class="section">
+        <li>"result of 'subvid' view for a row</li>
+        ...
+      </ul>
+
+    If you wish to use a different view for each entity, either subclass and
+    change the :attr:`item_vid` class attribute or specify a `subvid` argument
+    when calling this view.
+    """
     __regid__ = 'list'
     title = _('list')
     item_vid = 'listitem'
@@ -312,7 +388,21 @@
 
 
 class SimpleListView(ListItemView):
-    """list without bullets"""
+    """:__regid__: *simplelist*
+
+    Similar to :class:~cubicweb.web.views.baseviews.ListView but using '<div>'
+    instead of '<ul>'. It rely on '<div>' behaviour to separate items. HTML will
+    look like
+
+    .. sourcecode:: html
+
+      <div class="section">"result of 'subvid' view for a row</div>
+      ...
+
+
+    It relies on base :class:`~cubicweb.view.View` class implementation of the
+    :meth:`call` method to insert those <div>.
+    """
     __regid__ = 'simplelist'
     redirect_vid = 'incontext'
 
@@ -330,8 +420,13 @@
 
 
 class SameETypeListView(EntityView):
-    """list of entities of the same type, when asked explicitly for same etype list
-    view (for instance, display gallery if only images)
+    """:__regid__: *sameetypelist*
+
+    This view displays a list of entities of the same type, in HTML section
+    ('<div>') and call the view `sameetypelistitem` for each entity of the
+    result set. It's designed to get a more adapted global list when displayed
+    entities are all of the same type (for instance, display gallery if there
+    are only images entities).
     """
     __regid__ = 'sameetypelist'
     __select__ = EntityView.__select__ & one_etype_rset()
@@ -361,6 +456,11 @@
 
 
 class CSVView(SimpleListView):
+    """:__regid__: *csv*
+
+    This view displays each entity in a coma separated list. It is NOT related
+    to the well-known text file format.
+    """
     __regid__ = 'csv'
     redirect_vid = 'incontext'
 
@@ -377,12 +477,48 @@
                 self.w(u", ")
 
 
+# XXX to be documented views ###################################################
+
+class MetaDataView(EntityView):
+    """paragraph view of some metadata"""
+    __regid__ = 'metadata'
+    show_eid = True
+
+    def cell_call(self, row, col):
+        _ = self._cw._
+        entity = self.cw_rset.get_entity(row, col)
+        self.w(u'<div>')
+        if self.show_eid:
+            self.w(u'%s #%s - ' % (entity.dc_type(), entity.eid))
+        if entity.modification_date != entity.creation_date:
+            self.w(u'<span>%s</span> ' % _('latest update on'))
+            self.w(u'<span class="value">%s</span>, '
+                   % self._cw.format_date(entity.modification_date))
+        # entities from external source may not have a creation date (eg ldap)
+        if entity.creation_date:
+            self.w(u'<span>%s</span> ' % _('created on'))
+            self.w(u'<span class="value">%s</span>'
+                   % self._cw.format_date(entity.creation_date))
+        if entity.creator:
+            if entity.creation_date:
+                self.w(u' <span>%s</span> ' % _('by'))
+            else:
+                self.w(u' <span>%s</span> ' % _('created_by'))
+            self.w(u'<span class="value">%s</span>' % entity.creator.name())
+        meta = entity.cw_metainformation()
+        if meta['source']['uri'] != 'system':
+            self.w(u' (<span>%s</span>' % _('cw_source'))
+            self.w(u' <span class="value">%s</span>)' % meta['source']['uri'])
+        self.w(u'</div>')
+
+
 class TreeItemView(ListItemView):
     __regid__ = 'treeitem'
 
     def cell_call(self, row, col):
         self.wview('incontext', self.cw_rset, row=row, col=col)
 
+
 class TextSearchResultView(EntityView):
     """this view is used to display full-text search
 
@@ -425,26 +561,6 @@
         self.wview('oneline', self.cw_rset, row=row, col=col)
 
 
-# XXX bw compat
-
-from logilab.common.deprecation import class_moved
-
-try:
-    from cubicweb.web.views.tableview import TableView
-    TableView = class_moved(TableView)
-except ImportError:
-    pass # gae has no tableview module (yet)
-
-from cubicweb.web.views import boxes, xmlrss, primary
-PrimaryView = class_moved(primary.PrimaryView)
-SideBoxView = class_moved(boxes.SideBoxView)
-XmlView = class_moved(xmlrss.XMLView)
-XmlItemView = class_moved(xmlrss.XMLItemView)
-XmlRsetView = class_moved(xmlrss.XMLRsetView)
-RssView = class_moved(xmlrss.RSSView)
-RssItemView = class_moved(xmlrss.RSSItemView)
-
-
 class GroupByView(EntityView):
     """grouped view of a result set. The `group_key` method return the group
     key of an entities (a string or tuple of string).
@@ -550,3 +666,30 @@
         url = self.index_url(basepath, key, vtitle=vtitle)
         title = self._cw._('archive for %(author)s') % {'author': key}
         return tags.a(label, href=url, title=title)
+
+
+# bw compat ####################################################################
+
+from logilab.common.deprecation import class_moved, class_deprecated
+
+from cubicweb.web.views import boxes, xmlrss, primary, tableview
+PrimaryView = class_moved(primary.PrimaryView)
+SideBoxView = class_moved(boxes.SideBoxView)
+XmlView = class_moved(xmlrss.XMLView)
+XmlItemView = class_moved(xmlrss.XMLItemView)
+XmlRsetView = class_moved(xmlrss.XMLRsetView)
+RssView = class_moved(xmlrss.RSSView)
+RssItemView = class_moved(xmlrss.RSSItemView)
+TableView = class_moved(tableview.TableView)
+
+
+class SecondaryView(EntityView):
+    __metaclass__ = class_deprecated
+    __deprecation_warning__ = '[3.9] the secondary view is deprecated, use one of oneline/incontext/outofcontext'
+    __regid__ = 'secondary'
+    title = _('secondary')
+
+    def cell_call(self, row, col, **kwargs):
+        entity = self.cw_rset.get_entity(row, col)
+        self.w(u'&#160;')
+        self.wview('oneline', self.cw_rset, row=row, col=col)