backport stable 3.5
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 16 Sep 2009 17:29:45 +0200
branch3.5
changeset 3264 5d1f3f6c042d
parent 3263 5129918c671b (current diff)
parent 3258 6536ee4f37f7 (diff)
child 3265 96c8363b8f64
backport stable
web/uicfg.py
web/views/baseviews.py
web/views/formrenderers.py
--- a/dbapi.py	Wed Sep 16 17:27:04 2009 +0200
+++ b/dbapi.py	Wed Sep 16 17:29:45 2009 +0200
@@ -360,7 +360,7 @@
 # connection object ###########################################################
 
 class Connection(object):
-    """DB-API 2.0 compatible Connection object for CubicWebt
+    """DB-API 2.0 compatible Connection object for CubicWeb
     """
     # make exceptions available through the connection object
     ProgrammingError = ProgrammingError
--- a/doc/book/en/development/datamodel/inheritance.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/development/datamodel/inheritance.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -5,4 +5,14 @@
 When describing a data model, entities can inherit from other entities as is
 common in object-oriented programming.
 
+You have the possibility to adapt some entity attributes, as follow:
+
+.. sourcecode:: python
+
+    from cubes.OTHER_CUBE import entities
+    class EntityExample(entities.EntityExample):
+        def dc_long_title(self):
+            return '%s (%s)' % (self.name, self.description)
+
+
 XXX WRITME
--- a/doc/book/en/development/devcore/appobject.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/development/devcore/appobject.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -16,7 +16,7 @@
 We can find a certain number of attributes and methods defined in this class
 and common to all the application objects.
 
-At the recording, the following attributes are dynamically added to
+At recording time, the following attributes are dynamically added to
 the *subclasses*:
 
 * `vreg`, the `vregistry` of the instance
@@ -27,28 +27,15 @@
 
 * `req`, `Request` instance
 * `rset`, the *result set* associated to the object if necessary
-* `cursor`, rql cursor on the session
-
 
 :URL handling:
-  * `build_url(method=None, **kwargs)`, returns an absolute URL based on
-    the given arguments. The *controller* supposed to handle the response,
-    can be specified through the special parameter `method` (the connection
-    is theoretically done automatically :).
-
-  * `datadir_url()`, returns the directory of the instance data
-    (contains static files such as images, css, js...)
-
-  * `base_url()`, shortcut to `req.base_url()`
-
-  * `url_quote(value)`, version *unicode safe* of the function `urllib.quote`
+  * `build_url(*args, **kwargs)`, returns an absolute URL based on the
+    given arguments. The *controller* supposed to handle the response,
+    can be specified through the first positional parameter (the
+    connection is theoretically done automatically :).
 
 :Data manipulation:
 
-  * `etype_rset(etype, size=1)`, shortcut to `vreg.etype_rset()`
-
-  * `eid_rset(eid, rql=None, descr=True)`, returns a *result set* object for
-    the given eid
   * `entity(row, col=0)`, returns the entity corresponding to the data position
     in the *result set* associated to the object
 
@@ -57,15 +44,12 @@
 
 :Data formatting:
   * `format_date(date, date_format=None, time=False)` returns a string for a
-    mx date time according to instance's configuration
-  * `format_time(time)` returns a string for a mx date time according to
+    date time according to instance's configuration
+  * `format_time(time)` returns a string for a date time according to
     instance's configuration
 
 :And more...:
 
-  * `external_resource(rid, default=_MARKER)`, access to a value defined in the
-    configuration file `external_resource`
-
   * `tal_render(template, variables)`, renders a precompiled page template with
     variables in the given dictionary as context
 
@@ -73,13 +57,14 @@
   When we inherit from `AppObject` (even not directly), you *always* have to use
   **super()** to get the methods and attributes of the superclasses, and not
   use the class identifier.
+
   For example, instead of writting: ::
 
       class Truc(PrimaryView):
           def f(self, arg1):
               PrimaryView.f(self, arg1)
 
-  You'd better write: ::
+  You must write: ::
 
       class Truc(PrimaryView):
           def f(self, arg1):
--- a/doc/book/en/development/devcore/vreg.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/development/devcore/vreg.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -22,16 +22,15 @@
     Once the function `registration_callback(vreg)` is implemented, all the objects
     have to be explicitly registered as it disables the automatic object registering.
 
-* the old registration mechanism will be removed when there will be no reference
-  left to the registerers module in cubicweb and the library of cubes.
-
 Examples:
 
 .. sourcecode:: python
 
    # web/views/basecomponents.py
    def registration_callback(vreg):
+      # register everything in the module except SeeAlsoComponent
       vreg.register_all(globals().values(), __name__, (SeeAlsoVComponent,))
+      # conditionally register SeeAlsoVComponent
       if 'see_also' in vreg.schema:
           vreg.register(SeeAlsoVComponent)
 
@@ -66,7 +65,7 @@
 
 The object's selector is defined by its `__select__` class attribute.
 
-When two selectors are combined using the `&` operator (former `chainall`), it
+When two selectors are combined using the `&` operator (formerly `chainall`), it
 means that both should return a positive score. On success, the sum of scores is returned.
 
 When two selectors are combined using the `|` operator (former `chainfirst`), it
@@ -76,38 +75,38 @@
 Of course you can use paren to balance expressions.
 
 
-For instance, if you're selecting the primary (eg `id = 'primary'`) view (eg
+For instance, if you are selecting the primary (eg `id = 'primary'`) view (eg
 `__registry__ = 'view'`) for a result set containing a `Card` entity, 2 objects
 will probably be selectable:
 
-* the default primary view (`__select__ = implements('Any')`), meaning that the object is selectable for any kind of entity type
-
-* the specific `Card` primary view (`__select__ = implements('Card')`, meaning that the object is selectable for Card entities
+* the default primary view (`__select__ = implements('Any')`), meaning
+  that the object is selectable for any kind of entity type
 
-Other primary views specific to other entity types won't be selectable in this
-case. Among selectable objects, the implements selector will return a higher score
-to the second view since it's more specific, so it will be selected as expected.
+* the specific `Card` primary view (`__select__ = implements('Card')`,
+  meaning that the object is selectable for Card entities
+
+Other primary views specific to other entity types won't be selectable
+in this case. Among selectable objects, the implements selector will
+return a higher score than the second view since it's more specific,
+so it will be selected as expected.
 
 
 Example
 ````````
 
-XXX this part needs to be translated
-
-The goal : when on a Blog, one wants the RSS link to refer to blog
+The goal: when on a Blog, one wants the RSS link to refer to blog
 entries, not to the blog entity itself.
 
 To do that, one defines a method on entity classes that returns the
-RSS stream url for a given entity. With a default implementation on
-AnyEntity and a specific implementation on Blog, which will do what we
-want.
+RSS stream url for a given entity. The default implementation on
+AnyEntity and a specific implementation on Blog will do what we want.
 
-There's a limitation to this schema : when we have a result set
-containing several Blog entities (or different entities), we don't
-know on which entity to call the aforementioned method. In this case,
-we keep the current behaviour (e.g : call to limited_rql).
+But when we have a result set containing several Blog entities (or
+different entities), we don't know on which entity to call the
+aforementioned method. In this case, we keep the current behaviour
+(e.g : call to limited_rql).
 
-Hence we want two cases here, one for a single-entity rsets, the other
+Hence we have two cases here, one for a single-entity rsets, the other
 for multi-entities rsets.
 
 In web/views/boxes.py lies the RSSIconBox class. Look at its selector ::
@@ -116,7 +115,7 @@
     """just display the RSS icon on uniform result set"""
     __select__ = ExtResourcesBoxTemplate.__select__ & non_final_entity()
 
-It takes into account :
+It takes into account:
 
 * the inherited selection criteria (one has to look them up in the
   class hierarchy to know the details)
@@ -125,7 +124,7 @@
   entities (a 'final entity' being synonym for entity attribute)
 
 This matches our second case. Hence we have to provide a specific
-component for the first case ::
+component for the first case::
 
   class EntityRSSIconBox(RSSIconBox):
     """just display the RSS icon on uniform result set for a single entity"""
@@ -152,7 +151,7 @@
 ```````````````````````
 
 Selectors are to be used whenever arises the need of dispatching on
-the shape or content of a result set.
+the shape or content of a result set. That is, almost all the time.
 
 Debugging
 `````````
--- a/doc/book/en/development/devweb/internationalization.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/development/devweb/internationalization.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -45,7 +45,8 @@
 
 The goal of the *built-in* function `_` is only **to mark the
 translatable strings**, it will only return the string to translate
-it-self, but not its translation (it's actually refering to the `unicode` builtin).
+itself, but not its translation (it's actually another name for the
+`unicode` builtin).
 
 In the other hand the request's method `self.req._` is meant to retrieve the
 proper translation of translation strings in the requested language.
@@ -81,8 +82,8 @@
 
 
 * `i18ncubicweb` updates Cubicweb framework's translation
-  catalogs. Unless you work on the framework development, you don't
-  need to use this command.
+  catalogs. Unless you actually work on the framework itself, you
+  don't need to use this command.
 
 * `i18ncube` updates the translation catalogs of *one particular
   cube* (or of all cubes). After this command is
@@ -90,7 +91,7 @@
   directory of your template. This command will of course not remove
   existing translations still in use.
 
-* `i18ninstance` recompile the translation catalogs of *one particular
+* `i18ninstance` recompiles the translation catalogs of *one particular
   instance* (or of all instances) after the translation catalogs of
   its cubes have been updated. This command is automatically
   called every time you create or update your instance. The compiled
--- a/doc/book/en/development/devweb/views.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/development/devweb/views.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -34,26 +34,32 @@
     * the `category` attribute may be used in the interface to regroup related
       objects together
 
-At instantiation time, the standard `req`, `rset`, and `cursor`
-attributes are added and the `w` attribute will be set at rendering
-time.
+At instantiation time, the standard `req` and `rset` attributes are
+added and the `w` attribute will be set at rendering time.
 
-A view writes to its output stream thanks to its attribute `w` (`UStreamIO`).
+A view writes to its output stream thanks to its attribute `w` (an
+`UStreamIO`).
 
 The basic interface for views is as follows (remember that the result set has a
 tabular structure with rows and columns, hence cells):
 
-* `dispatch(**context)`, render the view by calling `call` or
+* `render(**context)`, render the view by calling `call` or
   `cell_call` depending on the given parameters
-* `call(**kwargs)`, call the view for a complete result set or null (default
-  implementation calls `cell_call()` on each cell of the result set)
-* `cell_call(row, col, **kwargs)`, call the view for a given cell of a result set
+
+* `call(**kwargs)`, call the view for a complete result set or null
+  (the default implementation calls `cell_call()` on each cell of the
+  result set)
+
+* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
+  result set
+
 * `url()`, returns the URL enabling us to get the view with the current
   result set
+
 * `view(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of identifier
   `__vid` on the given result set. It is possible to give a view identifier
   of fallback that will be used if the view requested is not applicable to the
-  result set
+  result set. This is actually defined on the AppObject class.
 
 * `wview(__vid, rset, __fallback_vid=None, **kwargs)`, similar to `view` except
   the flow is automatically passed in the parameters
@@ -70,8 +76,8 @@
 
 * `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
 * `StartupView`, start view that does not require a result set to apply to
-* `AnyRsetView`, view applied to any result set
-* `EmptyRsetView`, view applied to an empty result set
+* `AnyRsetView`, view applicable to any result set
+* `EmptyRsetView`, view applicable to an empty result set
 
 
 Examples of views class
@@ -103,11 +109,8 @@
         __select__ = one_line_rset() & match_search_state('linksearch') & implements('Any')
 
 
-Example of a view customization
--------------------------------
-
-[FIXME] XXX Example needs to be rewritten as it shows how to modify cell_call which
-contredicts our advise of not modifying it.
+Example of view customization and creation
+------------------------------------------
 
 We'll show you now an example of a ``primary`` view and how to customize it.
 
@@ -116,32 +119,26 @@
 
 .. sourcecode:: python
 
-   from cubicweb.view import EntityView
-   from cubicweb.selectors import implements
+  from cubicweb.selectors import implements
+  from cubicweb.web.views.primary improt Primaryview
 
-   class BlogEntryPrimaryView(EntityView):
-       id = 'primary'
-       __select__ =implements('Blog')
+  class BlogEntryPrimaryView(PrimaryView):
+    __select__ = PrimaryView.__select__ & implements('BlogEntry')
 
-       def cell_call(self, row, col):
-           entity = self.entity(row, col)
-           self.w(u'<h1>%s</h1>' % entity.title)
-           self.w(u'<p>published on %s in category %s</p>' % \
-                  (entity.publish_date.strftime('%Y-%m-%d'), entity.category))
-           self.w(u'<p>%s</p>' % entity.text)
+      def render_entity_attributes(self, entity):
+          self.w(u'<p>published on %s</p>' %
+                 entity.publish_date.strftime('%Y-%m-%d'))
+          super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
 
-The above source code defines a new primary view (`line 03`) for
-``BlogEntry`` (`line 05`).
+The above source code defines a new primary view for
+``BlogEntry``. The `id` class attribute is not repeated there since it
+is inherited through the `primary.PrimaryView` class.
 
-Since views are applied to result sets which can be tables of
-data, we have to recover the entity from its (row,col)-coordinates (`line 08`).
-We will get to this in more detail later.
+The selector for this view chains the selector of the inherited class
+with its own specific criterion.
 
 The view method ``self.w()`` is used to output data. Here `lines
-09-12` output HTML tags and values of the entity's attributes.
-
-When displaying the same blog entry as before, you will notice that the
-page is now looking much nicer. [FIXME: it is not clear to what this refers.]
+08-09` output HTML for the publication date of the entry.
 
 .. image:: ../../images/lax-book.09-new-view-blogentry.en.png
    :alt: blog entries now look much nicer
@@ -150,34 +147,74 @@
 
 .. sourcecode:: python
 
- class BlogPrimaryView(EntityView):
+ from logilab.mtconverter import xml_escape
+ from cubicweb.selectors import implements, one_line_rset
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogPrimaryView(PrimaryView):
      id = 'primary'
-     __select__ =implements('Blog')
+     __select__ = PrimaryView.__select__ & implements('Blog')
+     rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
+
+     def render_entity_relations(self, entity):
+         rset = self.req.execute(self.rql, {'b' : entity.eid})
+         for entry in rset.entities():
+             self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
+
+ class BlogEntryInBlogView(EntityView):
+     'inblogcontext'
+     __select__ = implements('BlogEntry')
 
      def cell_call(self, row, col):
-         entity = self.entity(row, col)
-         self.w(u'<h1>%s</h1>' % entity.title)
-         self.w(u'<p>%s</p>' % entity.description)
-         rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid)
-         self.wview('primary', rset)
+         entity = self.rset.get_entity(row, col)
+         self.w(u'<a href="%s" title="%s">%s</a>' %
+                entity.absolute_url(),
+                xml_escape(entity.content[:50]),
+                xml_escape(entity.description))
 
-In the above source code, `lines 01-08` are similar to the previous
-view we defined. [FIXME: defined where ?]
+This happens in two places. First we override the
+render_entity_relations method of a Blog's primary view. Here we want
+to display our blog entries in a custom way.
 
-At `line 09`, a simple request is made to build a result set with all
+At `line 10`, a simple request is made to build a result set with all
 the entities linked to the current ``Blog`` entity by the relationship
 ``entry_of``. The part of the framework handling the request knows
-about the schema and infer that such entities have to be of the
-``BlogEntry`` kind and retrieves them.
+about the schema and infers that such entities have to be of the
+``BlogEntry`` kind and retrieves them (in the prescribed publish_date
+order).
+
+The request returns a selection of data called a result set. Result
+set objects have an .entities() method returning a generator on
+requested entities (going transparently through the `ORM` layer).
+
+At `line 13` the view 'inblogcontext' is applied to each blog entry to
+output HTML. (Note that the 'inblogcontext' view is not defined
+whatsoever in *CubicWeb*. You are absolutely free to define whole view
+families.) We juste arrange to wrap each blogentry output in a 'p'
+html element.
 
-The request returns a selection of data called a result set. At
-`line 10` the view 'primary' is applied to this result set to output
-HTML.
+Next, we define the 'inblogcontext' view. This is NOT a primary view,
+with its well-defined sections (title, metadata, attribtues,
+relations/boxes). All a basic view has to define is cell_call.
+
+Since views are applied to result sets which can be tables of data, we
+have to recover the entity from its (row,col)-coordinates (`line
+20`). Then we can spit some HTML.
+
+But careful: all strings manipulated in *CubicWeb* are actually
+unicode strings. While web browsers are usually tolerant to incoherent
+encodings they are being served, we should not abuse it. Hence we have
+to properly escape our data. The xml_escape() function has to be used
+to safely fill (X)HTML elements from Python unicode strings.
+
 
 **This is to be compared to interfaces and protocols in object-oriented
 languages. Applying a given view called 'a_view' to all the entities
 of a result set only requires to have for each entity of this result set,
-an available view called 'a_view' which accepts the entity.**
+an available view called 'a_view' which accepts the entity.
+
+Instead of merely using type based dispatch, we do predicate dispatch
+which quite more powerful**
 
 Assuming we added entries to the blog titled `MyLife`, displaying it
 now allows to read its description and all its entries.
--- a/doc/book/en/development/webstdlib/baseviews.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/development/webstdlib/baseviews.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -30,10 +30,11 @@
 Entity views
 ````````````
 *incontext, outofcontext*
-    Those are used to display a link to an entity, depending if the entity is
-    considered as displayed in or out of context (of another entity).  By default
-    it respectively returns the result of `textincontext` and `textoutofcontext`
-    wrapped in a link leading to the primary view of the entity.
+    Those are used to display a link to an entity, depending on the
+    entity having to be displayed in or out of context
+    (of another entity).  By default it respectively returns the
+    result of `textincontext` and `textoutofcontext` wrapped in a link
+    leading to the primary view of the entity.
 
 *oneline*
     This view is used when we can't tell if the entity should be considered as
@@ -56,6 +57,12 @@
 *adaptedlistitem*
     This view redirects by default to the `outofcontext` view.
 
+*csv*
+    This view applies to entity groups, which are individually
+    displayed using the `incontext` view. It displays each entity as a
+    coma separated list. It is NOT related to the well-known text file
+    format.
+
 Text entity views
 ~~~~~~~~~~~~~~~~~
 *text*
--- a/doc/book/en/development/webstdlib/primary.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/development/webstdlib/primary.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -9,8 +9,9 @@
 Rendering methods and attributes for ``PrimaryView``
 ----------------------------------------------------
 
-By default, *CubicWeb* provides a primary view for each new entity type
-you create. The first view you might be interested in modifying.
+By default, *CubicWeb* provides a primary view for every available
+entity type. This is the first view you might be interested in
+modifying.
 
 Let's have a quick look at the EntityView ``PrimaryView`` as well as
 its rendering method
@@ -24,55 +25,63 @@
         show_attr_label = True
         show_rel_label = True
         skip_none = True
-        skip_attrs = ('eid', 'creation_date', 'modification_date')
-        skip_rels = ()
+        rsection = uicfg.primaryview_section
+        display_ctrl = uicfg.primaryview_display_ctrl
         main_related_section = True
 
         ...
 
     def cell_call(self, row, col):
         self.row = row
-        self.render_entity(self.complete_entity(row, col))
+        self.maxrelated = self.req.property_value('navigation.related-limit')
+        entity = self.complete_entity(row, col)
+        self.render_entity(entity)
 
     def render_entity(self, entity):
-        """return html to display the given entity"""
-        siderelations = []
         self.render_entity_title(entity)
         self.render_entity_metadata(entity)
         # entity's attributes and relations, excluding meta data
         # if the entity isn't meta itself
-        self.w(u'<div>')
+        boxes = self._prepare_side_boxes(entity)
+        if boxes or hasattr(self, 'render_side_related'):
+            self.w(u'<table width="100%"><tr><td style="width: 75%">')
+        self.render_entity_summary(entity)
         self.w(u'<div class="mainInfo">')
-        self.render_entity_attributes(entity, siderelations)
-        self.w(u'</div>')
         self.content_navigation_components('navcontenttop')
+        self.render_entity_attributes(entity)
         if self.main_related_section:
-            self.render_entity_relations(entity, siderelations)
+            self.render_entity_relations(entity)
         self.w(u'</div>')
         # side boxes
-        self.w(u'<div class="primaryRight">')
-        self.render_side_related(entity, siderelations)
-        self.w(u'</div>')
-        self.w(u'<div class="clear"></div>')
+        if boxes or hasattr(self, 'render_side_related'):
+            self.w(u'</td><td>')
+            self.w(u'<div class="primaryRight">')
+            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')
 
     ...
 
-``cell_call`` is executed for each entity of a result set and apply ``render_entity``.
+``cell_call`` is executed for each entity of a result set.
 
 The methods you want to modify while customizing a ``PrimaryView`` are:
 
 *render_entity_title(self, entity)*
     Renders the entity title based on the assumption that the method
-    ``def content_title(self)`` is implemented for the given entity type.
+    ``def dc_title(self)`` is implemented for the given entity type.
 
 *render_entity_metadata(self, entity)*
-    Renders the entity metadata based on the assumption that the method
-    ``def summary(self)`` is implemented for the given entity type.
+    Renders the entity metadata by calling the 'metadata' view on the
+    entity. This generic view is in cubicweb.views.baseviews.
 
-*render_entity_attributes(self, entity, siderelations)*
-    Renders all the attribute of an entity with the exception of attribute
-    of type `Password` and `Bytes`.
+*render_entity_attributes(self, entity)*
+    Renders all the attribute of an entity with the exception of
+    attribute of type `Password` and `Bytes`. The skip_none class
+    attribute controls the display of None valued attributes.
 
 *content_navigation_components(self, context)*
     This method is applicable only for entity type implementing the interface
@@ -81,15 +90,15 @@
     entities of this type, either at the top or at the bottom of the page
     given the context (navcontent{top|bottom}).
 
-*render_entity_relations(self, entity, siderelations)*
+*render_entity_relations(self, entity)*
     Renders all the relations of the entity in the main section of the page.
 
-*render_side_related(self, entity, siderelations)*
+*render_side_boxes(self, entity, boxes)*
     Renders all the relations of the entity in a side box. This is equivalent
     to *render_entity_relations* in addition to render the relations
     in a box.
 
-Also, please note that by setting the following attributes in you class,
+Also, please note that by setting the following attributes in your class,
 you can already customize some of the rendering:
 
 *show_attr_label*
--- a/doc/book/en/intro/concepts/index.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/intro/concepts/index.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -59,15 +59,15 @@
 
 .. image:: ../../images/archi_globale.en.png
 
-The command ``cubicweb-ctl list`` displays the list of instances installed on
-your system.
+The command ``cubicweb-ctl list`` also displays the list of instances
+installed on your system.
 
 On a Unix system, the instances are usually stored in the directory
 :file:`/etc/cubicweb.d/`. During development, the :file:`~/etc/cubicweb.d/`
 directory is looked up, as well as the paths in :envvar:`CW_INSTANCES_DIR`
 environment variable.
 
-The term application is used to refer at "something that should do something as a
+The term application is used to refer to "something that should do something as a
 whole", eg more like a project and so can refer to an instance or to a cube,
 depending on the context. This book will try to use *application*, *cube* and
 *instance* as appropriate.
@@ -77,7 +77,7 @@
 
 The data repository [#]_ provides access to one or more data sources (including
 SQL databases, LDAP repositories, Mercurial or Subversion version control
-systems, other CubicWeb repositories, GAE's DataStore, etc).
+systems, other CubicWeb instance repositories, GAE's DataStore, etc).
 
 All interactions with the repository are done using the Relation Query Language
 (RQL). The repository federates the data sources and hides them from the
@@ -99,13 +99,13 @@
 Web Engine
 ----------
 
-The web engine replies to http requests and runs the user interface and most of
-the application logic.
+The web engine replies to http requests and runs the user interface
+and most of the application logic.
 
-By default the web engine provides a generated user interface based on the data
-model of the instance. Entities can be created, displayed, updated and
-deleted. As the default user interface is not very fancy, it is usually
-necessary to develop your own.
+By default the web engine provides a default user interface based on
+the data model of the instance. Entities can be created, displayed,
+updated and deleted. As the default user interface is not very fancy,
+it is usually necessary to develop your own.
 
 Schema (Data Model)
 -------------------
@@ -120,7 +120,7 @@
 `Date`, `Time`, `Datetime`, `Interval`, `Password`, `Bytes`, `RichString`. See
 :ref:`yams.BASE_TYPES` for details.
 
-A `relation type` is used to define a binary oriented relation between two
+A `relation type` is used to define an oriented binary relation between two
 entity types.  The left-hand part of a relation is named the `subject` and the
 right-hand part is named the `object`.
 
@@ -143,8 +143,6 @@
 Registries and Objects
 ----------------------
 
-XXX registry, register, registries, registers ???
-
 Application objects
 ~~~~~~~~~~~~~~~~~~~
 
@@ -159,15 +157,15 @@
 
   object's `__registry__` : object's `id` : [list of app objects]
 
-The base class of appobjects is `AppRsetObject` (module `cubicweb.appobject`).
+The base class of appobjects is `AppObject` (module `cubicweb.appobject`).
 
 The `vregistry`
 ~~~~~~~~~~~~~~~
 
-At startup, the `registry` or registers base, inspects a number of directories
-looking for compatible classes definition. After a recording process, the objects
-are assigned to registers so that they can be selected dynamically while the
-instance is running.
+At startup, the `registry` inspects a number of directories looking
+for compatible classes definition. After a recording process, the
+objects are assigned to registers so that they can be selected
+dynamically while the instance is running.
 
 Selectors
 ~~~~~~~~~
@@ -185,7 +183,7 @@
   that case, the object with the greatest score is selected. There should always
   be a single appobject with a greater score than others.
 
-* get all appobjects applying to a context by specifying a registry.In
+* get all appobjects applying to a context by specifying a registry. In
   that case, every object with the a postive score is selected.
 
 * get the object within a particular registry/identifier. In that case no
@@ -195,10 +193,9 @@
 Selector sets are the glue that tie views to the data model. Using them
 appropriately is an essential part of the construction of well behaved cubes.
 
-
 When no score is higher than the others, an exception is raised in development
 mode to let you know that the engine was not able to identify the view to
-apply. This error is silented in production mode and one of the objects with the
+apply. This error is silenced in production mode and one of the objects with the
 higher score is picked.
 
 If no object has a positive score, ``NoSelectableObject`` exception is raised.
@@ -231,7 +228,14 @@
 Result set
 ~~~~~~~~~~
 
-XXX feed me
+Every request made (using RQL) to the data repository returns an
+object we call a Result Set. It enables easy use of the retrieved
+data, providing a translation layer between the backend's native
+datatypes and *CubicWeb* schema's EntityTypes.
+
+Result sets provide access to the raw data, yielding either basic
+Python data types, or schema-defined high-level entities, in a
+straightforward way.
 
 
 Views
@@ -246,4 +250,31 @@
 -----
 ** *CubicWeb* provides an extensible data repository **
 
-XXX feed me.
+The data model defined using Yams types allows to express the data
+model in a comfortable way. However several aspects of the data model
+can not be expressed there. For instance:
+
+* managing computed attributes
+
+* enforcing complicated structural invariants
+
+* real-world side-effects linked to data events (email notification
+  being a prime example)
+
+The hook system is much like the triggers of an SQL database engine,
+except that:
+
+* it is not limited to one specific SQL backend (every one of them
+  having an idiomatic way to encode triggers), nor to SQL backends at
+  all (think about LDAP or a Subversion repository)
+
+* it is well-coupled to the rest of the framework
+
+Hooks are basically functions that dispatch on both:
+
+* events : after/before add/update/delete on entities/relations
+
+* entity or relation types
+
+They are an essential building block of any moderately complicated
+cubicweb application.
--- a/doc/book/en/intro/tutorial/create-cube.rst	Wed Sep 16 17:27:04 2009 +0200
+++ b/doc/book/en/intro/tutorial/create-cube.rst	Wed Sep 16 17:29:45 2009 +0200
@@ -3,12 +3,12 @@
 Create your cube
 ----------------
 
-The packages ``cubicweb`` and ``cubicweb-dev`` installs a command line tool
-for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide range of
-commands described in details in :ref:`cubicweb-ctl`.
+The packages ``cubicweb`` and ``cubicweb-dev`` install a command line
+tool for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide
+range of commands described in details in :ref:`cubicweb-ctl`.
 
-Once your *CubicWeb* development environment is set up, you can create a new
-cube::
+Once your *CubicWeb* development environment is set up, you can create
+a new cube::
 
   cubicweb-ctl newcube blog
 
@@ -40,15 +40,15 @@
 
 
 A Blog has a title and a description. The title is a string that is
-required by the class EntityType and must be less than 50 characters.
-The description is a string that is not constrained.
+required and must be less than 50 characters.  The
+description is a string that is not constrained.
 
 A BlogEntry has a title, a publish_date and a content. The title is a
 string that is required and must be less than 100 characters. The
 publish_date is a Date with a default value of TODAY, meaning that
 when a BlogEntry is created, its publish_date will be the current day
 unless it is modified. The content is a string that will be indexed in
-the full-text index and has no constraint.
+the database full-text index and has no constraint.
 
 A BlogEntry also has a relationship ``entry_of`` that links it to a
 Blog. The cardinality ``?*`` means that a BlogEntry can be part of
@@ -172,9 +172,9 @@
 Define your entity views
 ------------------------
 
-Each entity defined in a model inherits default views allowing
-different rendering of the data. You can redefine each of them
-according to your needs and preferences. So let's see how the
+Each entity defined in a model is associated with default views
+allowing different rendering of the data. You can redefine each of
+them according to your needs and preferences. So let's see how the
 views are defined.
 
 
@@ -183,72 +183,74 @@
 
 A view is defined by a Python class which includes:
 
-  - an identifier (all objects in *CubicWeb* are entered in a registry
-    and this identifier will be used as a key)
+  - an identifier (all objects in *CubicWeb* are recorded in a
+    registry and this identifier will be used as a key)
 
   - a filter to select the result sets it can be applied to
 
-A view has a set of methods complying
-with the `View` class interface (`cubicweb.common.view`).
+A view has a set of methods complying with the `View` class interface
+(`cubicweb.common.view`).
 
 *CubicWeb* provides a lot of standard views for the type `EntityView`;
 for a complete list, read the code in directory ``cubicweb/web/views/``.
 
-A view is applied on a `result set` which contains a set of
-entities we are trying to display. *CubicWeb* uses a selector
-mechanism which computes for each available view a score:
-the view with the highest score is then used to display the given `result set`.
-The standard library of selectors is in
-``cubicweb.common.selector`` and a library of methods used to
-compute scores is available in ``cubicweb.vregistry.vreq``.
+A view is applied on a `result set` which contains a set of entities
+we are trying to display. *CubicWeb* uses a selector mechanism which
+computes for each available view a score: the view with the highest
+score is then used to display the given `result set`.  The standard
+library of selectors is in ``cubicweb.selector``.
 
 It is possible to define multiple views for the same identifier
 and to associate selectors and filters to allow the application
-to find the best way to render the data.
+to find the most appropriate way to render the data.
 
-For example, the view named ``primary`` is the one used to display
-a single entity. We will now show you how to customize this view.
+For example, the view named ``primary`` is the one used to display a
+single entity. We will now show you how to create a primary view for
+BlogEntry.
 
 
-View customization
-~~~~~~~~~~~~~~~~~~
+Primary view customization
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you wish to modify the way a `BlogEntry` is rendered, you will have
+to subclass the `primary` view, for instance in the module ``views``
+of the cube ``cubes/blog/views.py``.
+
+The standard primary view is the most sophisticated view of all. It
+has more than a call() method. It is a template. Actually the entry
+point calls the following sequence of (redefinable) methods:
+
+ * render_entity_title
 
-If you wish to modify the way a `BlogEntry` is rendered, you will have to
-overwrite the `primary` view defined in the module ``views`` of the cube
-``cubes/blog/views.py``.
+ * render_entity_metadata
+
+ * render_entity_attributes
+
+ * render_entity_relations
 
-We can for example add in front of the publication date a prefix specifying
-that the date we see is the publication date.
+ * render_side_boxes
+
+Excepted side boxes, we can see all of them already in action in the
+blog entry view. This is all described in more details in
+:ref:`primary`.
+
+We can for example add in front of the publication date a prefix
+specifying that the date we see is the publication date.
 
 To do so, please apply the following changes:
 
 .. sourcecode:: python
 
-  from cubicweb.web.views import baseviews
-
-
-  class BlogEntryPrimaryView(baseviews.PrimaryView):
-
-    accepts = ('BlogEntry',)
-
-    def render_entity_title(self, entity):
-        self.w(u'<h1>%s</h1>' % html_escape(entity.dc_title()))
-
-    def content_format(self, entity):
-        return entity.view('reledit', rtype='content_format')
+  from cubicweb.selectors import implements
+  from cubicweb.web.views import primary
 
-    def cell_call(self, row, col):
-        entity = self.entity(row, col)
+  class BlogEntryPrimaryView(primary.PrimaryView):
+    __select__ = implements('BlogEntry')
 
-        # display entity attributes with prefixes
-        self.w(u'<h1>%s</h1>' % entity.title)
-        self.w(u'<p>published on %s</p>' % entity.publish_date.strftime('%Y-%m-%d'))
-        self.w(u'<p>%s</p>' % entity.content)
-
-        # display relations
-        siderelations = []
-        if self.main_related_section:
-            self.render_entity_relations(entity, siderelations)
+      def render_entity_attributes(self, entity):
+          self.w(u'<p>published on %s</p>' %
+                 entity.publish_date.strftime('%Y-%m-%d'))
+          super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
 
 .. note::
   When a view is modified, it is not required to restart the instance
--- a/web/uicfg.py	Wed Sep 16 17:27:04 2009 +0200
+++ b/web/uicfg.py	Wed Sep 16 17:29:45 2009 +0200
@@ -156,6 +156,7 @@
                            'CWUser': 'system',
                            'CWGroup': 'system',
                            'CWPermission': 'system',
+                           'CWCache': 'system',
                            'BaseTransition': 'hidden',
                            }
 
--- a/web/views/baseviews.py	Wed Sep 16 17:27:04 2009 +0200
+++ b/web/views/baseviews.py	Wed Sep 16 17:29:45 2009 +0200
@@ -15,6 +15,8 @@
 __docformat__ = "restructuredtext en"
 _ = unicode
 
+from datetime import timedelta
+
 from rql import nodes
 
 from logilab.mtconverter import TransformError, xml_escape, xml_escape
@@ -77,6 +79,13 @@
                 self.w(entity.printable_value(rtype, value, format=format))
                 return
         if etype in ('Time', 'Interval'):
+            if etype == 'Interval' and isinstance(value, (int, long)):
+                # `date - date`, unlike `datetime - datetime` gives an int
+                # (number of days), not a timedelta
+                # XXX should rql be fixed to return Int instead of Interval in
+                #     that case? that would be probably the proper fix but we
+                #     loose information on the way...
+                value = timedelta(days=value)
             # value is DateTimeDelta but we have no idea about what is the
             # reference date here, so we can only approximate years and months
             if format == 'text/html':
--- a/web/views/formrenderers.py	Wed Sep 16 17:27:04 2009 +0200
+++ b/web/views/formrenderers.py	Wed Sep 16 17:29:45 2009 +0200
@@ -502,6 +502,7 @@
             w(form.view('inline-creation', None, etype=targettype,
                         peid=entity.eid, ptype=entity.e_schema,
                         rtype=rschema, role=role))
+            existant = True
         # we can create more than one related entity, we thus display a link
         # to add new related entities
         if form.should_display_add_new_relation_link(rschema, existant, card):