web/component.py
changeset 1808 aa09e20dd8c0
parent 1661 00340ebedc24
child 1977 606923dff11b
--- a/web/component.py	Tue May 05 17:18:49 2009 +0200
+++ b/web/component.py	Thu May 14 12:48:11 2009 +0200
@@ -1,71 +1,72 @@
 """abstract component class and base components definition for CubicWeb web client
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
 
-from cubicweb.common.appobject import Component, SingletonComponent
-from cubicweb.common.utils import merge_dicts
-from cubicweb.common.view import VComponent, SingletonVComponent
-from cubicweb.common.registerers import action_registerer
-from cubicweb.common.selectors import (paginated_rset, one_line_rset,
-                                       rql_condition, accept, primary_view,
-                                       match_context_prop, has_relation,
-                                       etype_rtype_selector)
-from cubicweb.common.uilib import html_escape
+from logilab.common.deprecation import class_renamed
+from logilab.mtconverter import html_escape
+
+from cubicweb import role
+from cubicweb.utils import merge_dicts
+from cubicweb.view import View, Component
+from cubicweb.selectors import (
+    paginated_rset, one_line_rset, primary_view, match_context_prop,
+    partial_has_related_entities, condition_compat, accepts_compat,
+    has_relation_compat)
 
 _ = unicode
 
-
-class EntityVComponent(VComponent):
+class EntityVComponent(Component):
     """abstract base class for additinal components displayed in content
     headers and footer according to:
-    
+
     * the displayed entity's type
     * a context (currently 'header' or 'footer')
 
     it should be configured using .accepts, .etype, .rtype, .target and
     .context class attributes
     """
-    
+
     __registry__ = 'contentnavigation'
-    __registerer__ = action_registerer    
-    __selectors__ = (one_line_rset, primary_view,
-                     match_context_prop, etype_rtype_selector,
-                     has_relation, accept,
-                     rql_condition)
-    
+    __select__ = one_line_rset() & primary_view() & match_context_prop()
+    registered = accepts_compat(has_relation_compat(condition_compat(View.registered)))
+
     property_defs = {
         _('visible'):  dict(type='Boolean', default=True,
                             help=_('display the box or not')),
         _('order'):    dict(type='Int', default=99,
                             help=_('display order of the component')),
         _('context'):  dict(type='String', default='header',
-                            vocabulary=(_('navtop'), _('navbottom'), 
+                            vocabulary=(_('navtop'), _('navbottom'),
                                         _('navcontenttop'), _('navcontentbottom')),
                             #vocabulary=(_('header'), _('incontext'), _('footer')),
                             help=_('context where this component should be displayed')),
         _('htmlclass'):dict(type='String', default='mainRelated',
                             help=_('html class of the component')),
     }
-    
-    accepts = ('Any',)
+
     context = 'navcontentbottom' # 'footer' | 'header' | 'incontext'
-    condition = None
-    
-    def call(self, view):
-        return self.cell_call(0, 0, view)
 
-    def cell_call(self, row, col, view):
+    def call(self, view=None):
+        return self.cell_call(0, 0, view=view)
+
+    def cell_call(self, row, col, view=None):
         raise NotImplementedError()
 
-    
-class NavigationComponent(VComponent):
+
+class NavigationComponent(Component):
     """abstract base class for navigation components"""
-    __selectors__ = (paginated_rset,)
     id = 'navigation'
+    __select__ = paginated_rset()
+
+    property_defs = {
+        _('visible'):  dict(type='Boolean', default=True,
+                            help=_('display the component or not')),
+        }
+
     page_size_property = 'navigation.page-size'
     start_param = '__start'
     stop_param = '__stop'
@@ -74,21 +75,8 @@
     previous_page_link_templ = next_page_link_templ = page_link_templ
     no_previous_page_link = no_next_page_link = u''
 
-    @classmethod
-    def selected(cls, req, rset, row=None, col=None, page_size=None, **kwargs):
-        """by default web app objects are usually instantiated on
-        selection according to a request, a result set, and optional
-        row and col
-        """
-        instance = super(NavigationComponent, cls).selected(req, rset, row, col, **kwargs)
-        if page_size is not None:
-            instance.page_size = page_size
-        elif 'page_size' in req.form:
-            instance.page_size = int(req.form['page_size'])
-        return instance
-    
-    def __init__(self, req, rset):
-        super(NavigationComponent, self).__init__(req, rset)
+    def __init__(self, req, rset, **kwargs):
+        super(NavigationComponent, self).__init__(req, rset, **kwargs)
         self.starting_from = 0
         self.total = rset.rowcount
 
@@ -96,14 +84,20 @@
         try:
             return self._page_size
         except AttributeError:
-            self._page_size = self.req.property_value(self.page_size_property)
-            return self._page_size
+            page_size = self.extra_kwargs.get('page_size')
+            if page_size is None:
+                if 'page_size' in self.req.form:
+                    page_size = int(self.req.form['page_size'])
+                else:
+                    page_size = self.req.property_value(self.page_size_property)
+            self._page_size = page_size
+            return page_size
 
     def set_page_size(self, page_size):
         self._page_size = page_size
-        
+
     page_size = property(get_page_size, set_page_size)
-    
+
     def page_boundaries(self):
         try:
             stop = int(self.req.form[self.stop_param]) + 1
@@ -112,7 +106,7 @@
             start, stop = 0, self.page_size
         self.starting_from = start
         return start, stop
-        
+
     def clean_params(self, params):
         if self.start_param in params:
             del params[self.start_param]
@@ -151,25 +145,19 @@
 
 class RelatedObjectsVComponent(EntityVComponent):
     """a section to display some related entities"""
-    __selectors__ = (one_line_rset, primary_view,
-                     etype_rtype_selector, has_relation,
-                     match_context_prop, accept)
+    __select__ = EntityVComponent.__select__ & partial_has_related_entities()
+
     vid = 'list'
 
     def rql(self):
-        """override this method if you want to use a custom rql query.
-        """
+        """override this method if you want to use a custom rql query"""
         return None
-    
+
     def cell_call(self, row, col, view=None):
         rql = self.rql()
         if rql is None:
             entity = self.rset.get_entity(row, col)
-            if self.target == 'object':
-                role = 'subject'
-            else:
-                role = 'object'
-            rset = entity.related(self.rtype, role)
+            rset = entity.related(self.rtype, role(self))
         else:
             eid = self.rset[row][col]
             rset = self.req.execute(self.rql(), {'x': eid}, 'x')
@@ -178,3 +166,10 @@
         self.w(u'<div class="%s">' % self.div_class())
         self.wview(self.vid, rset, title=self.req._(self.title).capitalize())
         self.w(u'</div>')
+
+
+VComponent = class_renamed('VComponent', Component,
+                           'VComponent is deprecated, use Component')
+SingletonVComponent = class_renamed('SingletonVComponent', Component,
+                                    'SingletonVComponent is deprecated, use '
+                                    'Component and explicit registration control')