(merge)
authorJulien Jehannet <julien.jehannet@logilab.fr>
Thu, 19 Feb 2009 20:21:10 +0100
changeset 859 17555e9b9854
parent 858 e6ae125d5903 (current diff)
parent 842 224bb95cca09 (diff)
child 860 d9f86f23b9a3
(merge)
__pkginfo__.py
goa/test/data/bootstrap_packages
web/views/basetemplates.py
web/views/boxes.py
web/views/linkedData.py
--- a/common/migration.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/common/migration.py	Thu Feb 19 20:21:10 2009 +0100
@@ -312,12 +312,18 @@
         """a configuration option's type has changed"""
         self._option_changes.append(('typechanged', optname, oldtype, newvalue))
         
-    def cmd_add_cube(self, cube):
+    def cmd_add_cubes(self, cubes):
+        """modify the list of used cubes in the in-memory config
+        returns newly inserted cubes, including dependencies
+        """
+        if isinstance(cubes, basestring):
+            cubes = (cubes,)
         origcubes = self.config.cubes()
-        newcubes = [p for p in self.config.expand_cubes([cube]) 
+        newcubes = [p for p in self.config.expand_cubes(cubes) 
                        if not p in origcubes]
         if newcubes:
-            assert cube in newcubes
+            for cube in cubes:
+                assert cube in newcubes
             self.config.add_cubes(newcubes)
         return newcubes
 
--- a/common/selectors.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/common/selectors.py	Thu Feb 19 20:21:10 2009 +0100
@@ -161,13 +161,20 @@
 def paginated_rset(cls, req, rset, *args, **kwargs):
     """accept result sets with more rows than the page size
     """
-    if rset is None or len(rset) <= req.property_value('navigation.page-size'):
+    page_size = kwargs.get('page_size')
+    if page_size is None:
+        page_size = req.form.get('page_size')
+        if page_size is None:
+            page_size = req.property_value('navigation.page-size')
+        else:
+            page_size = int(page_size)
+    if rset is None or len(rset) <= page_size:
         return 0
     return 1
 largerset_selector = deprecated_function(paginated_rset)
 
 @lltrace
-def sorted_rset(cls, req, rset, row=None, col=None):
+def sorted_rset(cls, req, rset, row=None, col=None, **kwargs):
     """accept sorted result set"""
     rqlst = rset.syntax_tree()
     if len(rqlst.children) > 1 or not rqlst.children[0].orderby:
--- a/common/test/unittest_entity.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/common/test/unittest_entity.py	Thu Feb 19 20:21:10 2009 +0100
@@ -250,8 +250,7 @@
         self.assertListEquals(rbc(e.relations_by_category('generic')),
                               [('primary_email', 'subject'),
                                ('evaluee', 'subject'),
-                               ('for_user', 'object'),
-                               ('bookmarked_by', 'object')])
+                               ('for_user', 'object')])
         # owned_by is defined both as subject and object relations on EUser
         self.assertListEquals(rbc(e.relations_by_category('generated')),
                               [('last_login_time', 'subject'),
@@ -263,7 +262,8 @@
                                ('owned_by', 'subject'),
                                ('created_by', 'object'),
                                ('wf_info_for', 'object'),
-                               ('owned_by', 'object')])
+                               ('owned_by', 'object'),
+                               ('bookmarked_by', 'object')])
         e = self.etype_instance('Personne')
         self.assertListEquals(rbc(e.relations_by_category('primary')),
                               [('nom', 'subject'), ('eid', 'subject')])
--- a/devtools/repotest.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/devtools/repotest.py	Thu Feb 19 20:21:10 2009 +0100
@@ -3,7 +3,7 @@
 This module contains functions to initialize a new repository.
 
 :organization: Logilab
-:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
@@ -249,7 +249,8 @@
 _orig_select_principal = rqlannotation._select_principal
 
 def _select_principal(scope, relations):
-    return _orig_select_principal(scope, sorted(relations, key=lambda x: x.r_type))
+    return _orig_select_principal(scope, relations,
+                                  _sort=lambda rels: sorted(rels, key=lambda x: x.r_type))
 
 try:
     from cubicweb.server.msplanner import PartPlanInformation
--- a/doc/book/en/B0031-define-entities.en.txt	Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/B0031-define-entities.en.txt	Thu Feb 19 20:21:10 2009 +0100
@@ -55,13 +55,21 @@
 It is possible to manage attributes/relations in the simple or multiple
 editing form thanks to the following *rtags*: 
 
-* `primary`, indicates that an attribute or a relation has to be inserted
-  in the simple or multiple editing forms. In the case of a relation,
-  the related entity editing form will be included in the editing form.
+* `primary`, indicates that an attribute or a relation has to be
+  inserted **in the simple or multiple editing forms**. In the case of
+  a relation, the related entity editing form will be included in the
+  editing form and represented as a combobox. Each item of the
+  combobox is a link to an existing entity.
 
-* `secondary`, indicates that an attribute or a relation has to be inserted
-  in the simple editing form only. In the case of a relation, the related
-  entity editing form sill be included in the editing form.
+* `secondary`, indicates that an attribute or a relation has to be
+  inserted **in the simple editing form only**. In the case of a
+  relation, the related entity editing form will be included in the
+  editing form and represented as a combobox. Each item of the combobox
+  is a link to an existing entity.
+
+* `inlineview`, includes the target entity's form in the editing form
+  of the current entity. It allows to create the target entity in the
+  same time as the current entity.
 
 * `generic`, indicates that a relation has to be inserted in the simple
   editing form, in the generic box of relation creation.
--- a/doc/book/en/C012-create-instance.en.txt	Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/C012-create-instance.en.txt	Thu Feb 19 20:21:10 2009 +0100
@@ -24,11 +24,11 @@
 
 A cube defines entities, their views, their schemas and workflows
 in an independant directory located in ``/path/to/forest/cubicweb/cubes/``
-for a Mercurila installation or in ``/usr/share/cubicweb/cubes`` for
-a debian packages installation.
+for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for
+a debian package installation.
 
 When an instance is created, you list one or more cubes that your instance
-will use. Use a cube means having the entities defined in your cube's schema
+will use. Using a cube means having the entities defined in your cube's schema
 available in your instance as well as their views and workflows.
 
 .. note::
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z010-beginners.en.txt	Thu Feb 19 20:21:10 2009 +0100
@@ -0,0 +1,12 @@
+.. -*- coding: utf-8 -*-
+
+.. _QuickInstall:
+
+===========================================
+Quick Installation of a `CubicWeb` instance
+===========================================
+
+.. include:: C011-installation.en.txt
+.. include:: Z012-create-instance.en.txt
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z012-create-instance.en.txt	Thu Feb 19 20:21:10 2009 +0100
@@ -0,0 +1,79 @@
+.. -*- coding: utf-8 -*-
+
+Creation of your first instance
+===============================
+
+What is an instance?
+--------------------
+
+A `CubicWeb` instance is a container that
+refers to cubes and configuration parameters for your web application.
+Each instance is stored as a directory in ``~/etc/cubicweb.d`` which enables 
+us to run your application.
+
+What is a cube?
+---------------
+
+Cubes represent data and basic building bricks of your web applications :
+blogs, person, date, addressbook and a lot more.
+
+.. XXX They related to each other by a 'Schema' which is also the PostGres representation.
+
+Each cube defines entities, their views, their schemas and workflows
+in an independant directory located in ``/path/to/forest/cubicweb/cubes/``
+for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for
+a debian package installation. For example, the 'blog' cube defines the entities 
+blogs and blogentries.
+
+When an `CubicWeb` instance is created, you list the cubes that you want to use. 
+Using a cube means having the entities defined in your cube's schema
+available in your instance as well as their views and workflows.
+
+
+Creating a basic `CubicWeb` Instance 
+------------------------------------
+
+We can create an instance to view our
+application in a web browser. ::
+
+  cubicweb-ctl create blog myblog
+
+.. XXX or ::
+  
+.. XXX cubicweb-ctl create forge myforge
+
+
+.. note::
+   The commands used below are more detailled in the section dedicated to 
+   :ref:`cubicweb-ctl`.
+
+A series of questions will be prompted to you, the default answer is usually
+sufficient. You can allways modify the parameters later by editing
+configuration files. When a user/psswd is requested to access the database
+please use the login you create at the time you configured the database
+(:ref:`ConfigurationPostgres`).
+
+It is important to distinguish here the user used to access the database and
+the user used to login to the cubicweb application. When a `CubicWeb` application
+starts, it uses the login/psswd for the database to get the schema and handle
+low level transaction. But, when ``cubicweb-ctl create`` asks for
+a manager login/psswd of `CubicWeb`, it refers to an application user
+to administrate your web application. 
+The configuration files are stored in *~/etc/cubicweb.d/myblog/*. 
+
+To launch the web application, you just type ::
+
+  cubicweb-ctl start myblog
+
+You can see how it looks by
+visiting the URL `http://localhost:8080`. 
+To login, please use the cubicweb administrator login/psswd you 
+defined when you created the instance.
+
+To shutdown the instance ::
+
+  cubicweb-ctl stop myinstance
+
+.. XXX something like `cubicweb-ctl live-server intra` would be nice
+
+
--- a/doc/book/en/index.txt	Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/index.txt	Thu Feb 19 20:21:10 2009 +0100
@@ -29,7 +29,9 @@
 
 The hacker will join development at the forge_.
 
-The impatient will move right away to :ref:`MiseEnPlaceEnv`.
+The impatient will go strait away to :ref:`QuickInstall`.
+
+The impatient developper will move right away to :ref:`MiseEnPlaceEnv`.
 
 .. _Logilab: http://www.logilab.fr/
 .. _forge: http://www.cubicweb.org/project/
--- a/doc/book/en/makefile	Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/makefile	Thu Feb 19 20:21:10 2009 +0100
@@ -43,7 +43,7 @@
 #apydoc: 
 #	epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py
 apidoc:
-	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../
+	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../
 
 # run sphinx ###
 html:
--- a/doc/book/fr/makefile	Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/fr/makefile	Thu Feb 19 20:21:10 2009 +0100
@@ -43,7 +43,7 @@
 #apydoc: 
 #	epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py
 apidoc:
-	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../
+	epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../
 
 # run sphinx ###
 html:
--- a/entities/authobjs.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/entities/authobjs.py	Thu Feb 19 20:21:10 2009 +0100
@@ -1,3 +1,10 @@
+"""entity classes user and group entities
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
 from logilab.common.decorators import cached
 
 from cubicweb import Unauthorized
@@ -26,6 +33,7 @@
                   'in_group'   : 'primary', 
                   ('owned_by', '*', 'object') : ('generated', 'link'),
                   ('created_by','*','object') : ('generated', 'link'),
+                  ('bookmarked_by', '*', 'object'): ('generated', 'create'),
                   }
     
     # used by repository to check if  the user can log in or not
@@ -85,6 +93,13 @@
         """
         return self.matching_groups(group) == 1
 
+    def is_anonymous(self):
+        """ checks if user is an anonymous user"""
+        #FIXME on the web-side anonymous user is detected according
+        # to config['anonymous-user'], we don't have this info on
+        # the server side. 
+        return self.groups == frozenset(('guests', ))
+
     def owns(self, eid):
         if hasattr(self.req, 'unsafe_execute'):
             # use unsafe_execute on the repository side, in case
--- a/entities/lib.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/entities/lib.py	Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
 """entity classes for optional library entities
 
 :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"
--- a/goa/test/unittest_editcontroller.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/goa/test/unittest_editcontroller.py	Thu Feb 19 20:21:10 2009 +0100
@@ -17,7 +17,7 @@
     config.global_set_option('use-google-auth', False)
     config.global_set_option('schema-type', 'yams')
     config.global_set_option('included-cubes', ())
-    config.global_set_option('included-yams-cubes', ('eblog',))
+    config.global_set_option('included-yams-cubes', ('blog',))
     
     MODEL_CLASSES = ()
     from cubicweb.web.views import editcontroller
--- a/i18n/en.po	Thu Feb 19 20:19:05 2009 +0100
+++ b/i18n/en.po	Thu Feb 19 20:21:10 2009 +0100
@@ -376,6 +376,9 @@
 msgid "Problem occured"
 msgstr ""
 
+msgid "Project linked data"
+msgstr ""
+
 msgid "RQLExpression"
 msgstr "RQL expression"
 
@@ -717,6 +720,9 @@
 msgid "add"
 msgstr ""
 
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr "bookmark"
+
 msgid "add EEType add_permission RQLExpression subject"
 msgstr "rql expression for the add permission"
 
@@ -1311,6 +1317,9 @@
 msgid "created_by_object"
 msgstr "has created"
 
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr "creating bookmark for %(linkto)s"
+
 msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
 msgstr "creating constraint for attribute %(linkto)s"
 
@@ -1668,12 +1677,18 @@
 msgid "february"
 msgstr ""
 
+msgid "file tree view"
+msgstr ""
+
 msgid "final"
 msgstr ""
 
 msgid "firstname"
 msgstr ""
 
+msgid "foaf"
+msgstr ""
+
 msgid "follow"
 msgstr ""
 
@@ -1997,6 +2012,9 @@
 msgid "list"
 msgstr ""
 
+msgid "loading"
+msgstr ""
+
 msgid "log in"
 msgstr ""
 
@@ -2025,6 +2043,9 @@
 msgid "manage bookmarks"
 msgstr ""
 
+msgid "manage permissions"
+msgstr ""
+
 msgid "manage security"
 msgstr ""
 
@@ -2137,6 +2158,9 @@
 msgid "not authorized"
 msgstr ""
 
+msgid "not selected"
+msgstr ""
+
 msgid "not specified"
 msgstr ""
 
@@ -2173,6 +2197,15 @@
 msgid "ordernum"
 msgstr "order"
 
+msgid "owl (tbox+abox)"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
+msgid "owlaboxlight"
+msgstr ""
+
 msgid "owned_by"
 msgstr "owned by"
 
@@ -2416,6 +2449,9 @@
 msgid "select this entity"
 msgstr ""
 
+msgid "selected"
+msgstr ""
+
 msgid "semantic description of this attribute"
 msgstr ""
 
@@ -2541,6 +2577,9 @@
 msgid "task progression"
 msgstr ""
 
+msgid "tbox"
+msgstr ""
+
 msgid "text"
 msgstr ""
 
@@ -2617,6 +2656,9 @@
 msgid "transition_of_object"
 msgstr "use transitions"
 
+msgid "tree view"
+msgstr ""
+
 msgid "tuesday"
 msgstr ""
 
--- a/i18n/es.po	Thu Feb 19 20:19:05 2009 +0100
+++ b/i18n/es.po	Thu Feb 19 20:21:10 2009 +0100
@@ -381,6 +381,9 @@
 msgid "Problem occured"
 msgstr "Ha ocurrido un error"
 
+msgid "Project linked data"
+msgstr ""
+
 msgid "RQLExpression"
 msgstr "Expresión RQL"
 
@@ -738,6 +741,9 @@
 msgid "add"
 msgstr "agregar"
 
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr ""
+
 msgid "add EEType add_permission RQLExpression subject"
 msgstr "Definir una expresión RQL de agregación"
 
@@ -1359,6 +1365,9 @@
 msgid "created_by_object"
 msgstr "ha creado"
 
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr ""
+
 msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
 msgstr "creación condicionada por el atributo %(linkto)s"
 
@@ -1745,12 +1754,18 @@
 msgid "february"
 msgstr "febrero"
 
+msgid "file tree view"
+msgstr ""
+
 msgid "final"
 msgstr "final"
 
 msgid "firstname"
 msgstr "nombre"
 
+msgid "foaf"
+msgstr ""
+
 msgid "follow"
 msgstr "seguir la liga"
 
@@ -2090,6 +2105,9 @@
 msgid "list"
 msgstr "liste"
 
+msgid "loading"
+msgstr ""
+
 msgid "log in"
 msgstr "s'identifier"
 
@@ -2118,6 +2136,9 @@
 msgid "manage bookmarks"
 msgstr "gÈrer les signets"
 
+msgid "manage permissions"
+msgstr ""
+
 msgid "manage security"
 msgstr "gestion de la sÈcuritÈ"
 
@@ -2232,6 +2253,9 @@
 msgid "not authorized"
 msgstr "non autorisÈ"
 
+msgid "not selected"
+msgstr ""
+
 msgid "not specified"
 msgstr "non spÈcifiÈ"
 
@@ -2268,6 +2292,15 @@
 msgid "ordernum"
 msgstr "ordre"
 
+msgid "owl (tbox+abox)"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
+msgid "owlaboxlight"
+msgstr ""
+
 msgid "owned_by"
 msgstr "appartient ‡"
 
@@ -2521,6 +2554,9 @@
 msgid "select this entity"
 msgstr "sÈlectionner cette entitÈ"
 
+msgid "selected"
+msgstr ""
+
 msgid "semantic description of this attribute"
 msgstr "description sÈmantique de cet attribut"
 
@@ -2649,6 +2685,9 @@
 msgid "task progression"
 msgstr "avancement de la t‚che"
 
+msgid "tbox"
+msgstr ""
+
 msgid "text"
 msgstr "text"
 
@@ -2726,6 +2765,9 @@
 msgid "transition_of_object"
 msgstr "a pour transition"
 
+msgid "tree view"
+msgstr ""
+
 msgid "tuesday"
 msgstr "mardi"
 
--- a/i18n/fr.po	Thu Feb 19 20:19:05 2009 +0100
+++ b/i18n/fr.po	Thu Feb 19 20:21:10 2009 +0100
@@ -381,6 +381,9 @@
 msgid "Problem occured"
 msgstr "Une erreur est survenue"
 
+msgid "Project linked data"
+msgstr ""
+
 msgid "RQLExpression"
 msgstr "Expression RQL"
 
@@ -740,6 +743,9 @@
 msgid "add"
 msgstr "ajouter"
 
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr "signet"
+
 msgid "add EEType add_permission RQLExpression subject"
 msgstr "définir une expression RQL d'ajout"
 
@@ -1197,7 +1203,7 @@
 msgstr "la barre de requête rql, dans l'en-tête de page"
 
 msgid "components_rss_feed_url"
-msgstr ""
+msgstr "syndication rss"
 
 msgid "components_rss_feed_url_description"
 msgstr ""
@@ -1361,14 +1367,17 @@
 msgid "created_by_object"
 msgstr "a créé"
 
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr "création d'un signet pour %(linkto)s"
+
 msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
-msgstr "création contrainte pour l'attribut %(linkto)s"
+msgstr "création d'une contrainte pour l'attribut %(linkto)s"
 
 msgid "creating EConstraint (ENFRDef %(linkto)s constrained_by EConstraint)"
-msgstr "création contrainte pour la relation %(linkto)s"
+msgstr "création d'une contrainte pour la relation %(linkto)s"
 
 msgid "creating EFRDef (EFRDef relation_type ERType %(linkto)s)"
-msgstr "création attribut %(linkto)s"
+msgstr "création d'un attribut %(linkto)s"
 
 msgid "creating ENFRDef (ENFRDef relation_type ERType %(linkto)s)"
 msgstr "création relation %(linkto)s"
@@ -1744,12 +1753,18 @@
 msgid "february"
 msgstr "février"
 
+msgid "file tree view"
+msgstr "arborescence (fichiers)"
+
 msgid "final"
 msgstr "final"
 
 msgid "firstname"
 msgstr "prénom"
 
+msgid "foaf"
+msgstr "foaf"
+
 msgid "follow"
 msgstr "suivre le lien"
 
@@ -2091,6 +2106,9 @@
 msgid "list"
 msgstr "liste"
 
+msgid "loading"
+msgstr "chargement"
+
 msgid "log in"
 msgstr "s'identifier"
 
@@ -2119,6 +2137,9 @@
 msgid "manage bookmarks"
 msgstr "gérer les signets"
 
+msgid "manage permissions"
+msgstr "gestion des permissions"
+
 msgid "manage security"
 msgstr "gestion de la sécurité"
 
@@ -2233,6 +2254,9 @@
 msgid "not authorized"
 msgstr "non autorisé"
 
+msgid "not selected"
+msgstr "non sélectionné"
+
 msgid "not specified"
 msgstr "non spécifié"
 
@@ -2269,6 +2293,15 @@
 msgid "ordernum"
 msgstr "ordre"
 
+msgid "owl (tbox+abox)"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
+msgid "owlaboxlight"
+msgstr ""
+
 msgid "owned_by"
 msgstr "appartient à"
 
@@ -2522,6 +2555,9 @@
 msgid "select this entity"
 msgstr "sélectionner cette entité"
 
+msgid "selected"
+msgstr "sélectionné"
+
 msgid "semantic description of this attribute"
 msgstr "description sémantique de cet attribut"
 
@@ -2650,6 +2686,9 @@
 msgid "task progression"
 msgstr "avancement de la tâche"
 
+msgid "tbox"
+msgstr ""
+
 msgid "text"
 msgstr "text"
 
@@ -2727,6 +2766,9 @@
 msgid "transition_of_object"
 msgstr "a pour transition"
 
+msgid "tree view"
+msgstr "arborescence"
+
 msgid "tuesday"
 msgstr "mardi"
 
--- a/interfaces.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/interfaces.py	Thu Feb 19 20:21:10 2009 +0100
@@ -238,3 +238,7 @@
     def rss_feed_url(self):
         """return an url which layout sub-entities item
         """
+class ISIOC(Interface):
+    """interface for entities with sioc views"""
+    
+   
--- a/rset.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/rset.py	Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
 """The `ResultSet` class which is returned as result of a rql query
 
 :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"
@@ -60,11 +60,15 @@
     def __repr__(self):
         if not self.rows:
             return '<empty resultset for %r>' % self.rql
+        rows = self.rows
+        if len(rows) > 10:
+            rows = rows[:10] + ['...']
         if not self.description:
-            return '<resultset %r: %s>' % (self.rql, '\n'.join(str(r) for r in self.rows))
-        return '<resultset %r: %s>' % (self.rql,
-                                       '\n'.join('%s (%s)' % (r, d)
-                                                 for r, d in zip(self.rows, self.description)))
+            return '<resultset %r (%s rows): %s>' % (self.rql, len(self.rows),
+                                                     '\n'.join(str(r) for r in rows))
+        return '<resultset %r (%s rows): %s>' % (self.rql, len(self.rows),
+                                                 '\n'.join('%s (%s)' % (r, d)
+                                                           for r, d in zip(rows, self.description)))
 
     @cached
     def possible_actions(self):
@@ -464,7 +468,8 @@
         rqlst = self.syntax_tree()
         etype = self.description[row][col]
         if self.vreg.schema.eschema(etype).is_final():
-            # final type, find a better (ambiguous) one
+            # final type, find a better one to locate the correct subquery
+            # (ambiguous if possible) 
             for i in xrange(len(rqlst.children[0].selection)):
                 if i == col:
                     continue
@@ -476,18 +481,17 @@
                     locate_query_col = i
                     if len(self.column_types(i)) > 1:
                         break
-        # UNION query, find the subquery from which this entity has been
-        # found
+        # UNION query, find the subquery from which this entity has been found
         select = rqlst.locate_subquery(locate_query_col, etype, self.args)
         try:
             myvar = select.selection[col].variable
         except AttributeError:
-            # no .selection attribute is available
+            # not a variable
             return None, None
         rel = myvar.main_relation()
         if rel is not None:
             index = rel.children[0].variable.selected_index()
-            if index is not None:
+            if index is not None and self.rows[row][index]:
                 return self.get_entity(row, index), rel.r_type
         return None, None
 
--- a/server/migractions.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/server/migractions.py	Thu Feb 19 20:21:10 2009 +0100
@@ -264,13 +264,15 @@
             self.commit()
 
     def cmd_add_cube(self, cube, update_database=True):
+        self.cmd_add_cubes( (cube,), update_database)
+    
+    def cmd_add_cubes(self, cubes, update_database=True):
         """update_database is telling if the database schema should be updated
         or if only the relevant eproperty should be inserted (for the case where
         a cube has been extracted from an existing application, so the
         cube schema is already in there)
         """
-        newcubes = super(ServerMigrationHelper, self).cmd_add_cube(
-            cube)
+        newcubes = super(ServerMigrationHelper, self).cmd_add_cubes(cubes)
         if not newcubes:
             return
         for pack in newcubes:
@@ -279,22 +281,22 @@
         if not update_database:
             self.commit()
             return
-        self.new_schema = self.config.load_schema()
+        with_new_cubes = self.config.load_schema()
         new = set()
         # execute pre-create files
         for pack in reversed(newcubes):
             self.exec_event_script('precreate', self.config.cube_dir(pack))
         # add new entity and relation types
-        for rschema in self.new_schema.relations():
+        for rschema in with_new_cubes.relations():
             if not rschema in self.repo.schema:
                 self.cmd_add_relation_type(rschema.type)
                 new.add(rschema.type)
-        for eschema in self.new_schema.entities():
+        for eschema in with_new_cubes.entities():
             if not eschema in self.repo.schema:
                 self.cmd_add_entity_type(eschema.type)
                 new.add(eschema.type)
         # check if attributes has been added to existing entities
-        for rschema in self.new_schema.relations():
+        for rschema in with_new_cubes.relations():
             existingschema = self.repo.schema.rschema(rschema.type)
             for (fromtype, totype) in rschema.iter_rdefs():
                 if existingschema.has_rdef(fromtype, totype):
--- a/server/repository.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/server/repository.py	Thu Feb 19 20:21:10 2009 +0100
@@ -490,7 +490,7 @@
         session = self.internal_session()
         try:
             if session.execute('EUser X WHERE X login %(login)s', {'login': login}):
-                return
+                return False
             # we have to create the user
             user = self.vreg.etype_class('EUser')(session, None)
             if isinstance(password, unicode):
@@ -505,6 +505,7 @@
             session.commit()
         finally:
             session.close()
+        return True
         
     def connect(self, login, password, cnxprops=None):
         """open a connection for a given user
--- a/server/rqlannotation.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/server/rqlannotation.py	Thu Feb 19 20:21:10 2009 +0100
@@ -146,16 +146,17 @@
 
 class CantSelectPrincipal(Exception): pass
 
-def _select_principal(sqlscope, relations):
+def _select_principal(sqlscope, relations, _sort=lambda x:x):
     """given a list of rqlst relations, select one which will be used to
     represent an invariant variable (e.g. using on extremity of the relation
     instead of the variable's type table
     """
+    # _sort argument is there for test
     diffscope_rels = {}
     has_same_scope_rel = False
     ored_rels = set()
     diffscope_rels = set()
-    for rel in relations:
+    for rel in _sort(relations):
         # note: only eid and has_text among all final relations may be there
         if rel.r_type in ('eid', 'identity'):
             has_same_scope_rel = rel.sqlscope is sqlscope
@@ -175,18 +176,17 @@
                 if isinstance(common_parent(rel1, rel2), Or):
                     ored_rels.discard(rel1)
                     ored_rels.discard(rel2)
-    for rel in ored_rels:
+    for rel in _sort(ored_rels):
         if rel.sqlscope is sqlscope:
             return rel
         diffscope_rels.add(rel)
     # if DISTINCT query, can use variable from a different scope as principal
     # since introduced duplicates will be removed
     if sqlscope.stmt.distinct and diffscope_rels:
-        return iter(diffscope_rels).next()
+        return iter(_sort(diffscope_rels)).next()
     # XXX  could use a relation for a different scope if it can't generate
     # duplicates, so we would have to check cardinality
-    raise CantSelectPrincipal()
-    
+    raise CantSelectPrincipal()    
 
 def _select_main_var(relations):
     """given a list of rqlst relations, select one which will be used as main
--- a/server/session.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/server/session.py	Thu Feb 19 20:21:10 2009 +0100
@@ -21,6 +21,18 @@
 from cubicweb.common.utils import make_uid
 from cubicweb.server.rqlrewrite import RQLRewriter
 
+_ETYPE_PYOBJ_MAP = { bool: 'Boolean',
+                     int: 'Int',
+                     long: 'Int',
+                     float: 'Float',
+                     Decimal: 'Decimal',
+                     unicode: 'String',
+                     NoneType: None,
+                     Binary: 'Bytes',
+                     DateTimeType: 'Datetime',
+                     DateTimeDeltaType: 'Interval',
+                     }
+
 def etype_from_pyobj(value):
     """guess yams type from python value"""
     # note:
@@ -28,17 +40,7 @@
     # * use type(value) and not value.__class__ since mx instances have no
     #   __class__ attribute
     # * XXX Date, Time
-    return {bool: 'Boolean',
-            int: 'Int',
-            long: 'Int',
-            float: 'Float',
-            Decimal: 'Decimal',
-            unicode: 'String',
-            NoneType: None,
-            Binary: 'Bytes',
-            DateTimeType: 'Datetime',
-            DateTimeDeltaType: 'Interval',
-            }[type(value)]
+    return _ETYPE_PYOBJ_MAP[type(value)]
 
 def is_final(rqlst, variable, args):
     # try to find if this is a final var or not
@@ -58,35 +60,8 @@
         description.append(term.get_type(solution, args))
     return description
 
-#XXX rql <= 0.18.3 bw compat
 from rql import stmts
-if not hasattr(stmts.Union, 'get_variable_variables'):
-    def _union_get_variable_variables(self):
-        """return the set of variable names which take different type according to
-        the solution
-        """
-        change = set()
-        values = {}
-        for select in self.children:
-            change.update(select.get_variable_variables(values))
-        return change
-    stmts.Union.get_variable_variables = _union_get_variable_variables
-                        
-    def _select_get_variable_variables(self, _values=None):
-        """return the set of variable names which take different type according to
-        the solution
-        """
-        change = set()
-        if _values is None:
-            _values = {}
-        for solution in self.solutions:
-            for vname, etype in solution.iteritems():
-                if not vname in _values:
-                    _values[vname] = etype
-                elif _values[vname] != etype:
-                    change.add(vname)
-        return change
-    stmts.Select.get_variable_variables = _select_get_variable_variables
+assert hasattr(stmts.Union, 'get_variable_variables'), "You need RQL > 0.18.3"
 
 class Session(RequestSessionMixIn):
     """tie session id, user, connections pool and other session data all
--- a/server/test/unittest_rql2sql.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/server/test/unittest_rql2sql.py	Thu Feb 19 20:21:10 2009 +0100
@@ -805,7 +805,7 @@
      'F name "read", F require_group E, U in_group E)), U eid 1',
      '''SELECT A.eid, rel_documented_by0.eid_to
 FROM Affaire AS A LEFT OUTER JOIN documented_by_relation AS rel_documented_by0 ON (rel_documented_by0.eid_from=A.eid)
-WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.eid AND F.name=read AND rel_require_group2.eid_from=F.eid AND rel_in_group3.eid_from=1 AND rel_in_group3.eid_to=rel_require_group2.eid_to)))'''),
+WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.eid AND F.name=read AND rel_require_group2.eid_from=F.eid AND rel_in_group3.eid_to=rel_require_group2.eid_to AND rel_in_group3.eid_from=1)))'''),
 
     ("Any X WHERE X eid 12, P? connait X",
      '''SELECT X.eid
--- a/test/unittest_rset.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/test/unittest_rset.py	Thu Feb 19 20:21:10 2009 +0100
@@ -300,7 +300,13 @@
             attr = etype == 'Bookmark' and 'title' or 'name'
             self.assertEquals(entity[attr], n)
         
-    
+    def test_related_entity_optional(self):
+        e = self.add_entity('Bookmark', title=u'aaaa', path=u'path')
+        rset = self.execute('Any B,U,L WHERE B bookmarked_by U?, U login L')
+        entity, rtype = rset.related_entity(0, 2)
+        self.assertEquals(entity, None)
+        self.assertEquals(rtype, None)
+        
     def test_related_entity_union_subquery(self):
         e = self.add_entity('Bookmark', title=u'aaaa', path=u'path')
         rset = self.execute('Any X,N ORDERBY N WITH X,N BEING '
--- a/vregistry.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/vregistry.py	Thu Feb 19 20:21:10 2009 +0100
@@ -20,7 +20,7 @@
 
 
 :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"
@@ -105,7 +105,10 @@
                             "can't be used together")
         if '__select__' not in classdict and '__selectors__' in classdict:
             selectors = classdict['__selectors__']
-            classdict['__select__'] = classmethod(chainall(*selectors))
+            if len(selectors) > 1:
+                classdict['__select__'] = classmethod(chainall(*selectors))
+            else:
+                classdict['__select__'] = classmethod(selectors[0])
         return super(autoselectors, mcs).__new__(mcs, name, bases, classdict)
 
     def __setattr__(self, attr, value):
--- a/web/application.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/application.py	Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
 """CubicWeb web client application object
 
 :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"
@@ -317,6 +317,7 @@
             try:
                 ctrlid, rset = self.url_resolver.process(req, path)
                 controller = self.select_controller(ctrlid, req)
+                req.update_search_state()
                 result = controller.publish(rset=rset)
                 if req.cnx is not None:
                     # req.cnx is None if anonymous aren't allowed and we are
--- a/web/component.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/component.py	Thu Feb 19 20:21:10 2009 +0100
@@ -73,6 +73,19 @@
     selected_page_link_templ = u'<span class="selectedSlice"><a href="%s" title="%s">%s</a></span>'
     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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.preferences.js	Thu Feb 19 20:21:10 2009 +0100
@@ -0,0 +1,10 @@
+/* toggle visibility of an element by its id
+ * & set current visibility status in a cookie
+ * XXX whenever used outside of preferences, don't forget to
+ *     move me in a more appropriate place
+ */
+function toggle_and_remember_visibility(elemId, cookiename) {
+    jqNode(elemId).toggleClass('hidden');
+    async_remote_exec('set_cookie', cookiename,
+                      jQuery('#' + elemId).attr('class'));
+}
--- a/web/data/cubicweb.tabs.js	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/data/cubicweb.tabs.js	Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,6 @@
-function set_tab(tabname) {
+function set_tab(tabname, cookiename) {
     // set appropriate cookie
-    // XXX see if we can no just do it with jQuery
-    async_remote_exec('remember_active_tab', tabname);
+    async_remote_exec('set_cookie', cookiename, tabname);
     // trigger show + tabname event
     trigger_load(tabname);
 }
--- a/web/data/jquery.corner.js	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/data/jquery.corner.js	Thu Feb 19 20:21:10 2009 +0100
@@ -1,1 +1,178 @@
-if(!document.createElement('canvas').getContext){(function(){var m=Math;var y=m.round;var z=m.sin;var A=m.cos;var Z=10;var B=Z/2;function getContext(){if(this.context_){return this.context_}return this.context_=new CanvasRenderingContext2D_(this)}var C=Array.prototype.slice;function bind(f,b,c){var a=C.call(arguments,2);return function(){return f.apply(b,a.concat(C.call(arguments)))}}var D={init:function(a){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var b=a||document;b.createElement('canvas');b.attachEvent('onreadystatechange',bind(this.init_,this,b))}},init_:function(a){if(!a.namespaces['g_vml_']){a.namespaces.add('g_vml_','urn:schemas-microsoft-com:vml')}if(!a.styleSheets['ex_canvas_']){var b=a.createStyleSheet();b.owningElement.id='ex_canvas_';b.cssText='canvas{display:inline-block;overflow:hidden;'+'text-align:left;width:300px;height:150px}'+'g_vml_\\:*{behavior:url(#default#VML)}'}},i:function(a){if(!a.getContext){a.getContext=getContext;a.attachEvent('onpropertychange',onPropertyChange);a.attachEvent('onresize',onResize);var b=a.attributes;if(b.width&&b.width.specified){a.style.width=b.width.nodeValue+'px'}else{a.width=a.clientWidth}if(b.height&&b.height.specified){a.style.height=b.height.nodeValue+'px'}else{a.height=a.clientHeight}}return a}};function onPropertyChange(e){var a=e.srcElement;switch(e.propertyName){case'width':a.style.width=a.attributes.width.nodeValue+'px';a.getContext().clearRect();break;case'height':a.style.height=a.attributes.height.nodeValue+'px';a.getContext().clearRect();break}}function onResize(e){var a=e.srcElement;if(a.firstChild){a.firstChild.style.width=a.clientWidth+'px';a.firstChild.style.height=a.clientHeight+'px'}}D.init();var E=[];for(var i=0;i<16;i++){for(var j=0;j<16;j++){E[i*16+j]=i.toString(16)+j.toString(16)}}function createMatrixIdentity(){return[[1,0,0],[0,1,0],[0,0,1]]}function processStyle(a){var b,alpha=1;a=String(a);if(a.substring(0,3)=='rgb'){var c=a.indexOf('(',3);var d=a.indexOf(')',c+1);var e=a.substring(c+1,d).split(',');b='#';for(var i=0;i<3;i++){b+=E[Number(e[i])]}if(e.length==4&&a.substr(3,1)=='a'){alpha=e[3]}}else{b=a}return[b,alpha]}function processLineCap(a){switch(a){case'butt':return'flat';case'round':return'round';case'square':default:return'square'}}function CanvasRenderingContext2D_(a){this.m_=createMatrixIdentity();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle='#000';this.fillStyle='#000';this.lineWidth=1;this.lineJoin='miter';this.lineCap='butt';this.miterLimit=Z*1;this.globalAlpha=1;this.canvas=a;var b=a.ownerDocument.createElement('div');b.style.width=a.clientWidth+'px';b.style.height=a.clientHeight+'px';b.style.overflow='hidden';b.style.position='absolute';a.appendChild(b);this.element_=b;this.arcScaleX_=1;this.arcScaleY_=1}var F=CanvasRenderingContext2D_.prototype;F.clearRect=function(){this.element_.innerHTML='';this.currentPath_=[]};F.beginPath=function(){this.currentPath_=[]};F.moveTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'moveTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.lineTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'lineTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.bezierCurveTo=function(a,b,c,d,e,f){var p=this.getCoords_(e,f);var g=this.getCoords_(a,b);var h=this.getCoords_(c,d);this.currentPath_.push({type:'bezierCurveTo',cp1x:g.x,cp1y:g.y,cp2x:h.x,cp2y:h.y,x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.fillRect=function(a,b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.fill();this.currentPath_=[]};F.createLinearGradient=function(a,b,c,d){return new CanvasGradient_('gradient')};F.createRadialGradient=function(a,b,c,d,e,f){var g=new CanvasGradient_('gradientradial');g.radius1_=c;g.radius2_=f;g.focus_.x=a;g.focus_.y=b;return g};F.stroke=function(d){var e=[];var f=false;var a=processStyle(d?this.fillStyle:this.strokeStyle);var g=a[0];var h=a[1]*this.globalAlpha;var W=10;var H=10;e.push('<g_vml_:shape',' fillcolor="',g,'"',' filled="',Boolean(d),'"',' style="position:absolute;width:',W,';height:',H,';"',' coordorigin="0 0" coordsize="',Z*W,' ',Z*H,'"',' stroked="',!d,'"',' strokeweight="',this.lineWidth,'"',' strokecolor="',g,'"',' path="');var j=false;var k={x:null,y:null};var l={x:null,y:null};for(var i=0;i<this.currentPath_.length;i++){var p=this.currentPath_[i];var c;switch(p.type){case'moveTo':e.push(' m ');c=p;e.push(y(p.x),',',y(p.y));break;case'lineTo':e.push(' l ');e.push(y(p.x),',',y(p.y));break;case'close':e.push(' x ');p=null;break;case'bezierCurveTo':e.push(' c ');e.push(y(p.cp1x),',',y(p.cp1y),',',y(p.cp2x),',',y(p.cp2y),',',y(p.x),',',y(p.y));break;case'at':case'wa':e.push(' ',p.type,' ');e.push(y(p.x-this.arcScaleX_*p.radius),',',y(p.y-this.arcScaleY_*p.radius),' ',y(p.x+this.arcScaleX_*p.radius),',',y(p.y+this.arcScaleY_*p.radius),' ',y(p.xStart),',',y(p.yStart),' ',y(p.xEnd),',',y(p.yEnd));break}if(p){if(k.x==null||p.x<k.x){k.x=p.x}if(l.x==null||p.x>l.x){l.x=p.x}if(k.y==null||p.y<k.y){k.y=p.y}if(l.y==null||p.y>l.y){l.y=p.y}}}e.push(' ">');if(typeof this.fillStyle=='object'){var m={x:'50%',y:'50%'};var n=l.x-k.x;var o=l.y-k.y;var q=n>o?n:o;m.x=y(this.fillStyle.focus_.x/n*100+50)+'%';m.y=y(this.fillStyle.focus_.y/o*100+50)+'%';var r=[];if(this.fillStyle.type_=='gradientradial'){var s=this.fillStyle.radius1_/q*100;var t=this.fillStyle.radius2_/q*100-s}else{var s=0;var t=100}var u={offset:null,color:null};var v={offset:null,color:null};this.fillStyle.colors_.sort(function(a,b){return a.offset-b.offset});for(var i=0;i<this.fillStyle.colors_.length;i++){var w=this.fillStyle.colors_[i];r.push(w.offset*t+s,'% ',w.color,',');if(w.offset>u.offset||u.offset==null){u.offset=w.offset;u.color=w.color}if(w.offset<v.offset||v.offset==null){v.offset=w.offset;v.color=w.color}}r.pop();e.push('<g_vml_:fill',' color="',v.color,'"',' color2="',u.color,'"',' type="',this.fillStyle.type_,'"',' focusposition="',m.x,', ',m.y,'"',' colors="',r.join(''),'"',' opacity="',h,'" />')}else if(d){e.push('<g_vml_:fill color="',g,'" opacity="',h,'" />')}else{var x=Math.max(this.arcScaleX_,this.arcScaleY_)*this.lineWidth;e.push('<g_vml_:stroke',' opacity="',h,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',processLineCap(this.lineCap),'"',' weight="',x,'px"',' color="',g,'" />')}e.push('</g_vml_:shape>');this.element_.insertAdjacentHTML('beforeEnd',e.join(''))};F.fill=function(){this.stroke(true)};F.closePath=function(){this.currentPath_.push({type:'close'})};F.getCoords_=function(a,b){return{x:Z*(a*this.m_[0][0]+b*this.m_[1][0]+this.m_[2][0])-B,y:Z*(a*this.m_[0][1]+b*this.m_[1][1]+this.m_[2][1])-B}};function CanvasPattern_(){}G_vmlCMjrc=D})()}if(jQuery.browser.msie){document.execCommand("BackgroundImageCache",false,true)}(function($){var N=$.browser.msie;var O=N&&!window.XMLHttpRequest;var P=$.browser.opera;var Q=typeof document.createElement('canvas').getContext=="function";var R=function(i){return parseInt(i,10)||0};var S=function(a,b,c){var x=a,y;if(x.currentStyle){y=x.currentStyle[b]}else if(window.getComputedStyle){if(typeof arguments[2]=="string")b=c;y=document.defaultView.getComputedStyle(x,null).getPropertyValue(b)}return y};var T=function(a,p){return S(a,'border'+p+'Color','border-'+p.toLowerCase()+'-color')};var U=function(a,p){if(a.currentStyle&&!P){w=a.currentStyle['border'+p+'Width'];if(w=='thin')w=2;if(w=='medium'&&!(a.currentStyle['border'+p+'Style']=='none'))w=4;if(w=='thick')w=6}else{p=p.toLowerCase();w=document.defaultView.getComputedStyle(a,null).getPropertyValue('border-'+p+'-width')}return R(w)};var V=function(a,i){return a.tagName.toLowerCase()==i};var W=function(e,a,b,c,d){if(e=='tl')return a;if(e=='tr')return b;if(e=='bl')return c;if(e=='br')return d};var X=function(a,b,c,d,e,f,g){var h,curve_to;if(d.indexOf('rgba')!=-1){var i=/^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/;var j=i.exec(d);if(j){var k=[R(j[1]),R(j[2]),R(j[3])];d='rgb('+k[0]+', '+k[1]+', '+k[2]+')'}}var l=a.getContext('2d');if(b==1||g=='notch'){if(e>0&&b>1){l.fillStyle=f;l.fillRect(0,0,b,b);l.fillStyle=d;h=W(c,[0-e,0-e],[e,0-e],[0-e,e],[e,e]);l.fillRect(h[0],h[1],b,b)}else{l.fillStyle=d;l.fillRect(0,0,b,b)}return a}else if(g=='bevel'){h=W(c,[0,0,0,b,b,0,0,0],[0,0,b,b,b,0,0,0],[0,0,b,b,0,b,0,0],[b,b,b,0,0,b,b,b]);l.fillStyle=d;l.beginPath();l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);l.lineTo(h[4],h[5]);l.lineTo(h[6],h[7]);l.fill();if(e>0&&e<b){l.strokeStyle=f;l.lineWidth=e;l.beginPath();h=W(c,[0,b,b,0],[0,0,b,b],[b,b,0,0],[0,b,b,0]);l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);l.stroke()}return a}h=W(c,[0,0,b,0,b,0,0,b,0,0],[b,0,b,b,b,0,0,0,0,0],[0,b,b,b,0,b,0,0,0,b],[b,b,b,0,b,0,0,b,b,b]);l.fillStyle=d;l.beginPath();l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);if(c=='br')l.bezierCurveTo(h[4],h[5],b,b,h[6],h[7]);else l.bezierCurveTo(h[4],h[5],0,0,h[6],h[7]);l.lineTo(h[8],h[9]);l.fill();if(e>0&&e<b){var m=e/2;var n=b-m;h=W(c,[n,m,n,m,m,n],[n,n,n,m,m,m],[n,n,m,n,m,m,m,n],[n,m,n,m,m,n,n,n]);curve_to=W(c,[0,0],[0,0],[0,0],[b,b]);l.strokeStyle=f;l.lineWidth=e;l.beginPath();l.moveTo(h[0],h[1]);l.bezierCurveTo(h[2],h[3],curve_to[0],curve_to[1],h[4],h[5]);l.stroke()}return a};var Y=function(p,a){var b=document.createElement('canvas');b.setAttribute("height",a);b.setAttribute("width",a);b.style.display="block";b.style.position="absolute";b.className="jrCorner";Z(p,b);if(!Q&&N){if(typeof G_vmlCanvasManager=="object"){b=G_vmlCanvasManager.initElement(b)}else if(typeof G_vmlCMjrc=="object"){b=G_vmlCMjrc.i(b)}else{throw Error('Could not find excanvas');}}return b};var Z=function(p,a){if(p.is("table")){p.children("tbody").children("tr:first").children("td:first").append(a);p.css('display','block')}else if(p.is("td")){if(p.children(".JrcTdContainer").length===0){p.html('<div class="JrcTdContainer" style="padding:0px;position:relative;margin:-1px;zoom:1;">'+p.html()+'</div>');p.css('zoom','1');if(O){p.children(".JrcTdContainer").get(0).style.setExpression("height","this.parentNode.offsetHeight")}}p.children(".JrcTdContainer").append(a)}else{p.append(a)}};if(N){var ba=document.createStyleSheet();ba.media='print';ba.cssText='.jrcIECanvasDiv { display:none !important; }'}var bb=function(D){if(this.length==0||!(Q||N)){return this}if(D=="destroy"){return this.each(function(){var p,elm=$(this);if(elm.is(".jrcRounded")){if(typeof elm.data("ie6tmr.jrc")=='number')window.clearInterval(elm.data("ie6tmr.jrc"));if(elm.is("table"))p=elm.children("tbody").children("tr:first").children("td:first");else if(elm.is("td"))p=elm.children(".JrcTdContainer");else p=elm;p.children(".jrCorner").remove();elm.unbind('mouseleave.jrc').unbind('mouseenter.jrc').removeClass('jrcRounded').removeData('ie6tmr.jrc');if(elm.is("td"))elm.html(elm.children(".JrcTdContainer").html())}})}var o=(D||"").toLowerCase();var E=R((o.match(/(\d+)px/)||[])[1])||"auto";var F=((o.match(/(#[0-9a-f]+)/)||[])[1])||"auto";var G=/round|bevel|notch/;var H=((o.match(G)||['round'])[0]);var I=/hover/.test(o);var J=/oversized/.test(o);var K=o.match("hiddenparent");if(N){var G=/ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/;var L=((o.match(G)||['ie6fixinit'])[0])}var M={tl:/top|left|tl/.test(o),tr:/top|right|tr/.test(o),bl:/bottom|left|bl/.test(o),br:/bottom|right|br/.test(o)};if(!M.tl&&!M.tr&&!M.bl&&!M.br)M={tl:1,tr:1,bl:1,br:1};this.each(function(){var d=$(this),rbg=null,bg,s,b,pr;var a=this;var e=S(this,'display');var f=S(this,'position');var g=S(this,'lineHeight','line-height');if(F=="auto"){s=d.siblings(".jrcRounded:eq(0)");if(s.length>0){b=s.data("rbg.jrc");if(typeof b=="string"){rbg=b}}}if(K||rbg===null){var h=this.parentNode,hidden_parents=new Array(),a=0;while((typeof h=='object')&&!V(h,'html')){if(K&&S(h,'display')=='none'){hidden_parents.push({originalvisibility:S(h,'visibility'),elm:h});h.style.display='block';h.style.visibility='hidden'}var j=S(h,'backgroundColor','background-color');if(rbg===null&&j!="transparent"&&j!="rgba(0, 0, 0, 0)"){rbg=j}h=h.parentNode}if(rbg===null)rbg="#ffffff"}if(F=="auto"){bg=rbg;d.data("rbg.jrc",rbg)}else{bg=F}if(e=='none'){var k=S(this,'visibility');this.style.display='block';this.style.visibility='hidden';var l=true}else{var m=false}var n=d.height();var p=d.width();if(I){var q=o.replace(/hover|ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/g,"");if(L!='ie6nofix')q="ie6fixinit "+q;d.bind("mouseenter.jrc",function(){d.addClass('jrcHover');d.corner(q)});d.bind("mouseleave.jrc",function(){d.removeClass('jrcHover');d.corner(q)})}if(O&&L!='ie6nofix'){this.style.zoom=1;if(L!='ie6fixexpr'){if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}$(window).load(function(){if(L=='ie6fixonload'){if(d.css('height')=='auto')d.height(d.css('height'));if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}else if(L=='ie6fixwidthint'||L=='ie6fixheightint'||L=='ie6fixbothint'){var c,ie6FixFunction;if(L=='ie6fixheightint'){ie6FixFunction=function(){d.height('auto');var a=d.height();if(a%2!=0)a=a+1;d.css({height:a})}}else if(L=='ie6fixwidthint'){ie6FixFunction=function(){d.width('auto');var a=d.width();if(a%2!=0)a=a+1;d.css({width:a});d.data('lastWidth.jrc',d.get(0).offsetWidth)}}else if(L=='ie6fixbothint'){ie6FixFunction=function(){d.width('auto');d.height('auto');var a=d.width();var b=d.height();if(b%2!=0)b=b+1;if(a%2!=0)a=a+1;d.css({width:a,height:b})}}c=window.setInterval(ie6FixFunction,100);d.data("ie6tmr.jrc",c)}})}var r=n<p?this.offsetHeight:this.offsetWidth;if(E=="auto"){E=r/2;if(E>10)E=r/4}if(E>r/2&&!J){E=r/2}E=Math.floor(E);var t=U(this,'Top');var u=U(this,'Right');var v=U(this,'Bottom');var w=U(this,'Left');if(f=='static'&&!V(this,'td')){this.style.position='relative'}else if(f=='fixed'&&N&&!(document.compatMode=='CSS1Compat'&&!O)){this.style.position='absolute'}if(t+u+v+w>0){this.style.overflow='visible'}if(l)d.css({display:'none',visibility:k});if(typeof hidden_parents!="undefined"){for(var i=0;i<hidden_parents.length;i++){hidden_parents[i].elm.style.display='none';hidden_parents[i].elm.style.visibility=hidden_parents[i].originalvisibility}}var x=0-t,p_right=0-u,p_bottom=0-v,p_left=0-w;var y=(d.find("canvas").length>0);if(y){if(V(this,'table'))pr=d.children("tbody").children("tr:first").children("td:first");else if(V(this,'td'))pr=d.children(".JrcTdContainer");else pr=d}if(M.tl){bordersWidth=t<w?t:w;if(y)pr.children("canvas.jrcTL").remove();var z=X(Y(d,E),E,'tl',bg,bordersWidth,T(this,'Top'),H);$(z).css({left:p_left,top:x}).addClass('jrcTL')}if(M.tr){bordersWidth=t<u?t:u;if(y)pr.children("canvas.jrcTR").remove();var A=X(Y(d,E),E,'tr',bg,bordersWidth,T(this,'Top'),H);$(A).css({right:p_right,top:x}).addClass('jrcTR')}if(M.bl){bordersWidth=v<w?v:w;if(y)pr.children("canvas.jrcBL").remove();var B=X(Y(d,E),E,'bl',bg,bordersWidth,T(this,'Bottom'),H);$(B).css({left:p_left,bottom:p_bottom}).addClass('jrcBL')}if(M.br){bordersWidth=v<u?v:u;if(y)pr.children("canvas.jrcBR").remove();var C=X(Y(d,E),E,'br',bg,bordersWidth,T(this,'Bottom'),H);$(C).css({right:p_right,bottom:p_bottom}).addClass('jrcBR')}if(N)d.children('canvas.jrCorner').children('div').addClass('jrcIECanvasDiv');if(O&&L=='ie6fixexpr'){if(M.bl){B.style.setExpression("bottom","this.parentNode.offsetHeight % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])+1)")}if(M.br){C.style.setExpression("right","this.parentNode.offsetWidth  % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderRightWidth']))  : 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])+1)");C.style.setExpression("bottom","this.parentNode.offsetHeight % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])+1)")}if(M.tr){A.style.setExpression("right","this.parentNode.offsetWidth   % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderRightWidth']))  : 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])+1)")}}d.addClass('jrcRounded')});if(typeof arguments[1]=="function")arguments[1](this);return this};$.fn.corner=bb})(jQuery);
\ No newline at end of file
+/*
+ * jQuery corner plugin
+ *
+ * version 1.92 (12/18/2007)
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ */
+
+/**
+ * The corner() method provides a simple way of styling DOM elements.  
+ *
+ * corner() takes a single string argument:  $().corner("effect corners width")
+ *
+ *   effect:  The name of the effect to apply, such as round or bevel. 
+ *            If you don't specify an effect, rounding is used.
+ *
+ *   corners: The corners can be one or more of top, bottom, tr, tl, br, or bl. 
+ *            By default, all four corners are adorned. 
+ *
+ *   width:   The width specifies the width of the effect; in the case of rounded corners this 
+ *            will be the radius of the width. 
+ *            Specify this value using the px suffix such as 10px, and yes it must be pixels.
+ *
+ * For more details see: http://methvin.com/jquery/jq-corner.html
+ * For a full demo see:  http://malsup.com/jquery/corner/
+ *
+ *
+ * @example $('.adorn').corner();
+ * @desc Create round, 10px corners 
+ *
+ * @example $('.adorn').corner("25px");
+ * @desc Create round, 25px corners 
+ *
+ * @example $('.adorn').corner("notch bottom");
+ * @desc Create notched, 10px corners on bottom only
+ *
+ * @example $('.adorn').corner("tr dog 25px");
+ * @desc Create dogeared, 25px corner on the top-right corner only
+ *
+ * @example $('.adorn').corner("round 8px").parent().css('padding', '4px').corner("round 10px");
+ * @desc Create a rounded border effect by styling both the element and its parent
+ * 
+ * @name corner
+ * @type jQuery
+ * @param String options Options which control the corner style
+ * @cat Plugins/Corner
+ * @return jQuery
+ * @author Dave Methvin (dave.methvin@gmail.com)
+ * @author Mike Alsup (malsup@gmail.com)
+ */
+(function($) { 
+
+$.fn.corner = function(o) {
+    var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent);
+    function sz(el, p) { return parseInt($.css(el,p))||0; };
+    function hex2(s) {
+        var s = parseInt(s).toString(16);
+        return ( s.length < 2 ) ? '0'+s : s;
+    };
+    function gpc(node) {
+        for ( ; node && node.nodeName.toLowerCase() != 'html'; node = node.parentNode ) {
+            var v = $.css(node,'backgroundColor');
+            if ( v.indexOf('rgb') >= 0 ) { 
+                if ($.browser.safari && v == 'rgba(0, 0, 0, 0)')
+                    continue;
+                var rgb = v.match(/\d+/g); 
+                return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
+            }
+            if ( v && v != 'transparent' )
+                return v;
+        }
+        return '#ffffff';
+    };
+    function getW(i) {
+        switch(fx) {
+        case 'round':  return Math.round(width*(1-Math.cos(Math.asin(i/width))));
+        case 'cool':   return Math.round(width*(1+Math.cos(Math.asin(i/width))));
+        case 'sharp':  return Math.round(width*(1-Math.cos(Math.acos(i/width))));
+        case 'bite':   return Math.round(width*(Math.cos(Math.asin((width-i-1)/width))));
+        case 'slide':  return Math.round(width*(Math.atan2(i,width/i)));
+        case 'jut':    return Math.round(width*(Math.atan2(width,(width-i-1))));
+        case 'curl':   return Math.round(width*(Math.atan(i)));
+        case 'tear':   return Math.round(width*(Math.cos(i)));
+        case 'wicked': return Math.round(width*(Math.tan(i)));
+        case 'long':   return Math.round(width*(Math.sqrt(i)));
+        case 'sculpt': return Math.round(width*(Math.log((width-i-1),width)));
+        case 'dog':    return (i&1) ? (i+1) : width;
+        case 'dog2':   return (i&2) ? (i+1) : width;
+        case 'dog3':   return (i&3) ? (i+1) : width;
+        case 'fray':   return (i%2)*width;
+        case 'notch':  return width; 
+        case 'bevel':  return i+1;
+        }
+    };
+    o = (o||"").toLowerCase();
+    var keep = /keep/.test(o);                       // keep borders?
+    var cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]);  // corner color
+    var sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]);  // strip color
+    var width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10; // corner width
+    var re = /round|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dog/;
+    var fx = ((o.match(re)||['round'])[0]);
+    var edges = { T:0, B:1 };
+    var opts = {
+        TL:  /top|tl/.test(o),       TR:  /top|tr/.test(o),
+        BL:  /bottom|bl/.test(o),    BR:  /bottom|br/.test(o)
+    };
+    if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
+        opts = { TL:1, TR:1, BL:1, BR:1 };
+    var strip = document.createElement('div');
+    strip.style.overflow = 'hidden';
+    strip.style.height = '1px';
+    strip.style.backgroundColor = sc || 'transparent';
+    strip.style.borderStyle = 'solid';
+    return this.each(function(index){
+        var pad = {
+            T: parseInt($.css(this,'paddingTop'))||0,     R: parseInt($.css(this,'paddingRight'))||0,
+            B: parseInt($.css(this,'paddingBottom'))||0,  L: parseInt($.css(this,'paddingLeft'))||0
+        };
+
+        if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' in IE
+        if (!keep) this.style.border = 'none';
+        strip.style.borderColor = cc || gpc(this.parentNode);
+        var cssHeight = $.curCSS(this, 'height');
+
+        for (var j in edges) {
+            var bot = edges[j];
+            // only add stips if needed
+            if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) {
+                strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none');
+                var d = document.createElement('div');
+                $(d).addClass('jquery-corner');
+                var ds = d.style;
+
+                bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild);
+
+                if (bot && cssHeight != 'auto') {
+                    if ($.css(this,'position') == 'static')
+                        this.style.position = 'relative';
+                    ds.position = 'absolute';
+                    ds.bottom = ds.left = ds.padding = ds.margin = '0';
+                    if ($.browser.msie)
+                        ds.setExpression('width', 'this.parentNode.offsetWidth');
+                    else
+                        ds.width = '100%';
+                }
+                else if (!bot && $.browser.msie) {
+                    if ($.css(this,'position') == 'static')
+                        this.style.position = 'relative';
+                    ds.position = 'absolute';
+                    ds.top = ds.left = ds.right = ds.padding = ds.margin = '0';
+                    
+                    // fix ie6 problem when blocked element has a border width
+                    var bw = 0;
+                    if (ie6 || !$.boxModel)
+                        bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
+                    ie6 ? ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"') : ds.width = '100%';
+                }
+                else {
+                    ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' : 
+                                        (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px';                
+                }
+
+                for (var i=0; i < width; i++) {
+                    var w = Math.max(0,getW(i));
+                    var e = strip.cloneNode(false);
+                    e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px';
+                    bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild);
+                }
+            }
+        }
+    });
+};
+
+$.fn.uncorner = function(o) { return $('.jquery-corner', this).remove(); };
+    
+})(jQuery);
--- a/web/request.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/request.py	Thu Feb 19 20:21:10 2009 +0100
@@ -201,7 +201,7 @@
     def update_search_state(self):
         """update the current search state"""
         searchstate = self.form.get('__mode')
-        if not searchstate:
+        if not searchstate and self.cnx is not None:
             searchstate = self.get_session_data('search_state', 'normal')
         self.set_search_state(searchstate)
 
@@ -212,7 +212,8 @@
         else:
             self.search_state = ('linksearch', searchstate.split(':'))
             assert len(self.search_state[-1]) == 4
-        self.set_session_data('search_state', searchstate)
+        if self.cnx is not None:
+            self.set_session_data('search_state', searchstate)
 
     def update_breadcrumbs(self):
         """stores the last visisted page in session data"""
--- a/web/test/test_views.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/test/test_views.py	Thu Feb 19 20:21:10 2009 +0100
@@ -39,9 +39,9 @@
         self.view('table', rset, template=None, displayfilter=True, displaycols=[0,2])
         rset = self.execute('Any P,F,S LIMIT 1 WHERE P is EUser, P firstname F, P surname S')
         rset.req.form['rtype'] = 'firstname'
-        self.view('editrelation', rset, template=None, htmlcheck=False)
+        self.view('editrelation', rset, template=None)
         rset.req.form['rtype'] = 'use_email'
-        self.view('editrelation', rset, template=None, htmlcheck=False)
+        self.view('editrelation', rset, template=None)
         
 
     def test_sortable_js_added(self):
--- a/web/test/unittest_viewselector.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/test/unittest_viewselector.py	Thu Feb 19 20:21:10 2009 +0100
@@ -19,6 +19,7 @@
                                 treeview, idownloadable, wdoc, debug)
 from cubicweb.entities.lib import Card
 from cubicweb.interfaces import IMileStone
+from cubicweb.web.views import owl
 
 USERACTIONS = [('myprefs', actions.UserPreferencesAction),
                ('myinfos', actions.UserInfoAction),
@@ -74,7 +75,7 @@
                               ('index', startup.IndexView),
                               ('info', management.ProcessInformationView),
                               ('manage', startup.ManageView),
-                              ('owl', startup.OWLView),
+                              ('owl', owl.OWLView),
                               ('schema', startup.SchemaView),
                               ('systemepropertiesform', management.SystemEpropertiesForm)])
         # no entity but etype
@@ -97,6 +98,7 @@
                               ('filetree', treeview.FileTreeView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', baseviews.PrimaryView),
                               ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
@@ -117,6 +119,7 @@
                               ('filetree', treeview.FileTreeView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', baseviews.PrimaryView),
                               ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
@@ -137,6 +140,7 @@
                               ('filetree', treeview.FileTreeView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', baseviews.PrimaryView),
                               ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
@@ -163,8 +167,10 @@
                               ('ecsvexport', baseviews.CSVEntityView),
                               ('editable-table', tableview.EditableTableView),
                               ('filetree', treeview.FileTreeView),
+                              ('foaf', euser.FoafView),
                               ('list', baseviews.ListView),
                               ('oneline', baseviews.OneLineView),
+                              ('owlabox', owl.OWLABOXView),
                               ('primary', euser.EUserPrimaryView),
                               ('rsetxml', baseviews.XMLRsetView),
                               ('rss', baseviews.RssView),
--- a/web/views/basecontrollers.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/basecontrollers.py	Thu Feb 19 20:21:10 2009 +0100
@@ -60,7 +60,6 @@
     
     def publish(self, rset=None):
         """publish a request, returning an encoded string"""
-        self.req.update_search_state()
         template = self.req.property_value('ui.main-template')
         if template not in self.vreg.registry('templates') :
             template = self.template
@@ -453,7 +452,14 @@
         # link the new entity to the main entity
         rql = 'SET F %(rel)s T WHERE F eid %(eid_to)s, T eid %(eid_from)s' % {'rel' : rel, 'eid_to' : eid_to, 'eid_from' : eid_from}
         return eid_from
-    
+
+    def js_set_cookie(self, cookiename, cookievalue):
+        # XXX we should consider jQuery.Cookie
+        cookiename, cookievalue = str(cookiename), str(cookievalue)
+        cookies = self.req.get_cookie()
+        cookies[cookiename] = cookievalue
+        self.req.set_cookie(cookies, cookiename)
+
 class SendMailController(Controller):
     id = 'sendmail'
     require_groups = ('managers', 'users')
--- a/web/views/baseforms.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/baseforms.py	Thu Feb 19 20:21:10 2009 +0100
@@ -2,7 +2,7 @@
 or a list of entities of the same type
 
 :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"
@@ -33,6 +33,9 @@
     title = _('delete')
     domid = 'deleteconf'
     onsubmit = None
+    # don't use navigation, all entities asked to be deleted should be displayed
+    # else we will only delete the displayed page
+    need_navigation = False
     
     def call(self):
         """ask for confirmation before real deletion"""
@@ -392,17 +395,20 @@
                 if rschema != 'eid']
     
     def relations_form(self, entity, kwargs):
+        srels_by_cat = entity.srelations_by_category(('generic', 'metadata'), 'add')
+        if not srels_by_cat:
+            return u''
         req = self.req
         _ = self.req._
         label = u'%s :' % _('This %s' % entity.e_schema).capitalize()
         eid = entity.eid
         html = []
-        pendings = list(self.restore_pending_inserts(entity))
         w = html.append
         w(u'<fieldset class="subentity">')
         w(u'<legend class="iformTitle">%s</legend>' % label)
         w(u'<table id="relatedEntities">')
         for row in self.relations_table(entity):
+            # already linked entities
             if row[2]:
                 w(u'<tr><th class="labelCol">%s</th>' % row[0].display_name(req, row[1]))
                 w(u'<td>')
@@ -415,10 +421,12 @@
                 w(u'</ul>')
                 w(u'</td>')
                 w(u'</tr>')
+        pendings = list(self.restore_pending_inserts(entity))
         if not pendings:
             w(u'<tr><th>&nbsp;</th><td>&nbsp;</td></tr>')
         else:
             for row in pendings:
+                # soon to be linked to entities
                 w(u'<tr id="tr%s">' % row[1])
                 w(u'<th>%s</th>' % row[3])
                 w(u'<td>')
@@ -434,7 +442,8 @@
         w(u'<select id="relationSelector_%s" tabindex="%s" onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'
           % (eid, req.next_tabindex(), html_escape(dumps(eid))))
         w(u'<option value="">%s</option>' % _('select a relation'))
-        for i18nrtype, rschema, target in entity.srelations_by_category(('generic', 'metadata'), 'add'):
+        for i18nrtype, rschema, target in srels_by_cat:
+            # more entities to link to
             w(u'<option value="%s_%s">%s</option>' % (rschema, target, i18nrtype))
         w(u'</select>')
         w(u'</th>')
--- a/web/views/basetemplates.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/basetemplates.py	Thu Feb 19 20:21:10 2009 +0100
@@ -2,16 +2,18 @@
 """default templates 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 logilab.mtconverter import html_escape
 
 from cubicweb import NoSelectableObject, ObjectNotFound
 from cubicweb.common.view import Template, MainTemplate,  NOINDEX, NOFOLLOW
 from cubicweb.common.utils import make_uid
+from cubicweb.common.utils import UStringIO
 
 from cubicweb.web.views.baseviews import vid_from_rset
 
@@ -163,7 +165,10 @@
                                                  self.req, self.rset)
         if etypefilter and etypefilter.propval('visible'):
             etypefilter.dispatch(w=self.w)
-        self.pagination(self.req, self.rset, self.w, not (view and view.need_navigation))
+        self.nav_html = UStringIO()
+        self.pagination(self.req, self.rset, self.nav_html.write,
+                        not (view and view.need_navigation))
+        self.w(_(self.nav_html.getvalue()))
         self.w(u'<div id="contentmain">\n')
     
     def template_html_header(self, content_type, page_title, additional_headers=()):
@@ -199,6 +204,7 @@
             
     def template_footer(self, view=None):
         self.w(u'</div>\n') # close id=contentmain
+        self.w(_(self.nav_html.getvalue()))
         self.w(u'</div>\n') # closes id=pageContent
         self.content_footer(view)
         self.w(u'</td>\n')
@@ -419,7 +425,7 @@
                                             req._(ChangeLogView.title).lower()))
         self.w(u'<a href="%s">%s</a> | ' % (req.build_url('doc/about'),
                                             req._('about this site')))
-        self.w(u'© 2001-2008 <a href="http://www.logilab.fr">Logilab S.A.</a>')
+        self.w(u'© 2001-2009 <a href="http://www.logilab.fr">Logilab S.A.</a>')
         self.w(u'</div>')
 
 
--- a/web/views/baseviews.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/baseviews.py	Thu Feb 19 20:21:10 2009 +0100
@@ -57,14 +57,14 @@
     """
     id = 'final'
             
-    def cell_call(self, row, col, props=None, displaytime=False):
+    def cell_call(self, row, col, props=None, displaytime=False, format='text/html'):
         etype = self.rset.description[row][col]
         value = self.rset.rows[row][col]
         if etype == 'String':
             entity, rtype = self.rset.related_entity(row, col)
             if entity is not None:
                 # yes !
-                self.w(entity.printable_value(rtype, value))
+                self.w(entity.printable_value(rtype, value, format=format))
                 return
         if etype in ('Time', 'Interval'):
             _ = self.req._
@@ -639,7 +639,7 @@
                                     row=rowindex, col=colindex)
                 else:
                     val = self.view('final', rset, displaytime=True,
-                                    row=rowindex, col=colindex)
+                                    row=rowindex, col=colindex, format='text/plain')
                 w(simple_sgml_tag(tag, val, **attrs))
             w(u' </row>\n')
         w(u'</%s>\n' % self.xml_root)
@@ -747,7 +747,8 @@
                     content = self.view('textincontext', rset, 
                                         row=rowindex, col=colindex)
                 else:
-                    content = self.view('final', rset, displaytime=True,
+                    content = self.view('final', rset,
+                                        displaytime=True, format='text/plain',
                                         row=rowindex, col=colindex)
                 csvrow.append(content)                    
             writer.writerow(csvrow)
@@ -800,7 +801,7 @@
         rset, vid, divid, paginate = self.filter_box_context_info()
         self.w(u'<div id="%s">' % divid)
         self.pagination(self.req, rset, w=self.w)
-        self.wview(vid, rset)
+        self.wview(vid, rset, 'noresult')
         self.w(u'</div>')
 
     @cached
@@ -862,13 +863,8 @@
         assert rtype is not None, "rtype is mandatory for 'edirelation' view"
         targettype = self.req.form.get('targettype', targettype)
         role = self.req.form.get('role', role)
-        mode = entity.rtags.get_mode(rtype, targettype, role)
-        if mode == 'create':
-            return
         category = entity.rtags.get_category(rtype, targettype, role)
-        if category in ('generated', 'metadata'):
-            return
-        elif category in ('primary', 'secondary'):
+        if category in ('primary', 'secondary') or self.schema.rschema(rtype).is_final():
             if hasattr(entity, '%s_format' % rtype):
                 formatwdg = entity.get_widget('%s_format' % rtype, role)
                 self.w(formatwdg.edit_render(entity))
@@ -879,10 +875,8 @@
             self.w(u'%s %s %s' %
                    (wdg.render_error(entity), wdg.edit_render(entity),
                     wdg.render_help(entity),))
-        elif category == 'generic':
+        else:
             self._render_generic_relation(entity, rtype, role)
-        else:
-            self.error("oops, wrong category %s", category)
 
     def _render_generic_relation(self, entity, relname, role):
         text = self.req.__('add %s %s %s' % (entity.e_schema, relname, role))
--- a/web/views/boxes.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/boxes.py	Thu Feb 19 20:21:10 2009 +0100
@@ -10,14 +10,14 @@
 * startup views box
 
 :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 logilab.mtconverter import html_escape
 
-from cubicweb.common.selectors import (any_rset, appobject_selectable)
+from cubicweb.common.selectors import any_rset, appobject_selectable
 from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, BoxHtml, RawBoxItem
 from cubicweb.web.box import BoxTemplate, ExtResourcesBoxTemplate
 
@@ -175,17 +175,16 @@
 
     def call(self, **kwargs):
         box = BoxWidget(self.req._(self.title), self.id)
-        actions = [v for v in self.vreg.possible_views(self.req, self.rset)
-                   if v.category != 'startupview']
-        for category, actions in self.sort_actions(actions):
+        views = [v for v in self.vreg.possible_views(self.req, self.rset)
+                 if v.category != 'startupview']
+        for category, views in self.sort_actions(views):
             menu = BoxMenu(category)
-            for action in actions:
-                menu.append(self.box_action(action))
+            for view in views:
+                menu.append(self.box_action(view))
             box.append(menu)
         if not box.is_empty():
             box.render(self.w)
 
-
         
 class RSSIconBox(ExtResourcesBoxTemplate):
     """just display the RSS icon on uniform result set"""
@@ -203,23 +202,6 @@
         self.w(u'<a href="%s"><img src="%s" alt="rss"/></a>\n' % (html_escape(url), rss))
 
 
-## warning("schemabox ne marche plus pour le moment")
-## class SchemaBox(BoxTemplate):
-##     """display a box containing link to list of entities by type"""
-##     id = 'schema_box'
-##     visible = False # disabled by default
-##     title = _('entity list')
-##     order = 60
-        
-##     def call(self, **kwargs):
-##         box = BoxWidget(self.req._(title), self.id)
-##         for etype in self.config.etypes(self.req.user, 'read'):
-##             view = self.vreg.select_view('list', self.req, self.etype_rset(etype))
-##             box.append(self.mk_action(display_name(self.req, etype, 'plural'),
-##                                       view.url(), etype=etype))
-##         if not box.is_empty():
-##             box.render(self.w)
-
 class StartupViewsBox(BoxTemplate):
     """display a box containing links to all startup views"""
     id = 'startup_views_box'
--- a/web/views/euser.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/euser.py	Thu Feb 19 20:21:10 2009 +0100
@@ -14,12 +14,6 @@
 from cubicweb.web.form import EntityForm
 from cubicweb.web.views.baseviews import PrimaryView, EntityView
 
-try:
-    from hashlib import sha1 as sha 
-
-except ImportError:
-    from sha import sha
-
 class EUserPrimaryView(PrimaryView):
     accepts = ('EUser',)
     skip_attrs = ('firstname', 'surname')
@@ -38,7 +32,6 @@
         return  rschema.type in ['interested_in', 'tags', 
                                  'todo_by', 'bookmarked_by',
                                  ]
-
 class FoafView(EntityView):
     id = 'foaf'
     accepts = ('EUser',)
@@ -47,10 +40,10 @@
     content_type = 'text/xml'
 
     def call(self):
-        self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding)
-        self.w(u'<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\n')
-        self.w(u'xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"\n')
-        self.w(u'xmlns:foaf="http://xmlns.com/foaf/0.1/">\n')
+        self.w('''<?xml version="1.0" encoding="%s"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
+         xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self.req.encoding)
         for i in xrange(self.rset.rowcount):
             self.cell_call(i, 0)
         self.w(u'</rdf:RDF>\n')
@@ -72,10 +65,15 @@
                    % html_escape(entity.firstname))
         emailaddr = entity.get_email()
         if emailaddr:
-            self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(unicode(emailaddr)))
-            self.w(u'</foaf:Person>\n')
+            self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
+        self.w(u'</foaf:Person>\n')
 
-
+class FoafUsableView(FoafView):
+    id = 'foaf_usable'
+  
+    def call(self):
+        self.cell_call(0, 0)
+            
 class EditGroups(EntityForm):
     """displays a simple euser / egroups editable table"""
     
--- a/web/views/facets.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/facets.py	Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
 """the facets box and some basic facets
 
 :organization: Logilab
-:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
--- a/web/views/linkedData.py	Thu Feb 19 20:19:05 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-from logilab.mtconverter import html_escape
-
-from cubicweb.common.view import EntityView
-
-from urlparse import urlparse
-
-class LinkedDataProjectView(EntityView):
-    id = 'project_linked_data'
-    title = _('Project linked data')
-    accepts = ('Project',)
-    templatable = False
-    content_type = 'text/xml'
-
-    def call(self):
-        '''display all project attribut and project dependencies and external project (in doap format) if
-        it is related to'''
-
-        self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding)
-        self.w(u'''<rdf:RDF
-            xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-            xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
-            xmlns:owl="http://www.w3.org/2002/07/owl#"
-            xmlns:doap="http://usefulinc.com/ns/doap#"
-            >\n''')
-        for i in xrange(self.rset.rowcount):
-            self.cell_call(row=i, col=0)
-        self.w(u'</rdf:RDF>\n')
-            
-    def cell_call(self, row, col):
-        self.wview('project_linked_data_item', self.rset, row=row, col=col)
-    
-class LinkedDataProjectItemView(EntityView):
-    id = 'project_linked_data_item'
-    accepts = ('Project',)
-
-    def cell_call(self, row, col):
-        entity = self.complete_entity(row, col)
-        self.w(u'<Project rdf:about="%s">\n' % html_escape(entity.absolute_url()))
-        self.w(u'  <name>%s</name>\n' % html_escape(unicode(entity.dc_title())))
-        self.w(u'  <doap:created>%s</doap:created>\n' % (entity.creation_date.strftime('%Y-%m-%d')))
-        self.w(u'  <summary>%s</summary>\n' % html_escape(unicode(entity.summary)))
-        self.w(u'  <doap:description>%s</doap:description>\n' % html_escape(unicode(entity.description)))           
-        self.w(u'  <url>%s</url>\n' % html_escape(entity.url or entity.absolute_url()))
-        if entity.modification_date:
-            self.w(u'<doap:revision>%s</doap:revision>\n'% (entity.modification_date.strftime('%Y-%m-%d')))
-        if entity.vcsurl:
-            self.w(u'''<vcurl>
-                          <doap:browse rdf:resource="%s" />
-                       </vcurl>''' % html_escape(entity.vcsurl))
-        if entity.reporturl:
-            self.w(u'<reporturl>"%s"</vcurl>' % html_escape(entity.vcsurl))             
-        
-        if entity.downloadurl:
-            self.w(u'  <doap:file-release>%s</doap:file-release>\n' % html_escape(entity.downloadurl))
-        liste = urlparse(entity.absolute_url())
-        internal_address = liste[1]
-        for externalproject in entity.uses:
-            self.w(u'<uses>\n')
-            if externalproject.e_schema == 'ExtProject':
-                if externalproject.absolute_url().find(internal_address) > 0:
-                    self.w(u'<!--wrong external url-->')
-                self.w(u' <ExtProject>%s</ExtProject>'% externalproject.absolute_url())
-            else:
-                self.w(u'<Project>%s</Project>'% externalproject.absolute_url())
-            self.w(u'</uses>\n')
-        for externalproject in entity.recommends:
-            self.w(u'<recommends>\n')
-            if externalproject.e_schema == 'ExtProject':
-                if externalproject.absolute_url().find(internal_address) > 0:
-                    self.w(u'<!--wrong external url-->')
-                self.w(u'<ExtProject>%s</ExtProject>'% externalproject.absolute_url())
-            else:
-                self.w(u'<Project>%s</Project>'% externalproject.absolute_url())                
-            self.w(u'%s</recommends>'% externalproject.absolute_url())       
-
-        self.w(u'</Project>\n')
-
-    
--- a/web/views/management.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/management.py	Thu Feb 19 20:21:10 2009 +0100
@@ -13,17 +13,16 @@
 
 from cubicweb.common.utils import UStringIO
 from cubicweb.common.view import AnyRsetView, StartupView, EntityView
-from cubicweb.common.uilib import (html_traceback, rest_traceback, html_escape,
-                                toggle_link)
+from cubicweb.common.uilib import html_traceback, rest_traceback
 from cubicweb.common.selectors import (yes, one_line_rset,
-                                    accept_rset, none_rset,
-                                    chainfirst, chainall)
+                                       accept_rset, none_rset,
+                                       chainfirst, chainall)
 from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, stdmsgs
 from cubicweb.web.widgets import StaticComboBoxWidget
 from cubicweb.web.form import FormMixIn
 
 _ = unicode
-            
+
 def begin_form(w, entity, redirectvid, redirectpath=None, msg=None):
     w(u'<form method="post" action="%s">\n' % entity.req.build_url('edit'))
     w(u'<fieldset>\n')
@@ -42,10 +41,10 @@
     """display security information for a given entity"""
     id = 'security'
     title = _('security')
-        
+
     def cell_call(self, row, col):
-        self.req.add_js('cubicweb.edition.js')            
-        self.req.add_css('cubicweb.acl.css')            
+        self.req.add_js('cubicweb.edition.js')
+        self.req.add_css('cubicweb.acl.css')
         entity = self.entity(row, col)
         w = self.w
         _ = self.req._
@@ -90,7 +89,7 @@
             w(u'<td>%s</td>' % u'<br/>'.join(expr.expression for expr in rqlexprs))
             w(u'</tr>\n')
         w(u'</table>')
-        
+
     def owned_by_edit_form(self, entity):
         self.w('<h3>%s</h3>' % self.req._('ownership'))
         begin_form(self.w, entity, 'security', msg= _('ownerships have been changed'))
@@ -169,7 +168,7 @@
         wdg = newperm.get_widget('label')
         w(u'<td>%s</td>\n' % wdg.edit_render(newperm))
         wdg = newperm.get_widget('require_group')
-        w(u'<td>%s</td>\n' % wdg.edit_render(newperm))            
+        w(u'<td>%s</td>\n' % wdg.edit_render(newperm))
         w(u'<td>%s</td></tr>\n' % self.button_ok())
         w(u'</table>')
         w(u'</fieldset></form>\n')
@@ -178,12 +177,12 @@
         return (u'<input class="validateButton" type="submit" name="submit" value="%s"/>'
                 % self.req._(stdmsgs.BUTTON_OK))
 
-        
+
 class ErrorView(AnyRsetView):
     """default view when no result has been found"""
     __selectors__ = (yes,)
     id = 'error'
-    
+
     def page_title(self):
         """returns a title according to the result set - used for the
         title in the HTML header
@@ -192,11 +191,11 @@
 
     def call(self):
         req = self.req.reset_headers()
-        _ = req._
+        _ = req._; w = self.w
         ex = req.data.get('ex')#_("unable to find exception information"))
         excinfo = req.data.get('excinfo')
         title = _('an error occured')
-        self.w(u'<h2>%s</h2>' % title)
+        w(u'<h2>%s</h2>' % title)
         if 'errmsg' in req.data:
             ex = req.data['errmsg']
             exclass = None
@@ -205,53 +204,53 @@
             ex = exc_message(ex, req.encoding)
         if excinfo is not None and self.config['print-traceback']:
             if exclass is None:
-                self.w(u'<div class="tb">%s</div>'
+                w(u'<div class="tb">%s</div>'
                        % html_escape(ex).replace("\n","<br />"))
             else:
-                self.w(u'<div class="tb">%s: %s</div>'
+                w(u'<div class="tb">%s: %s</div>'
                        % (exclass, html_escape(ex).replace("\n","<br />")))
-            self.w(u'<hr />')
-            self.w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, ''))
+            w(u'<hr />')
+            w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, ''))
         else:
-            self.w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />")))
+            w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />")))
         # if excinfo is not None, it's probably not a bug
         if excinfo is None:
             return
         vcconf = self.config.vc_config()
-        self.w(u"<div>")
+        w(u"<div>")
         eversion = vcconf.get('cubicweb', _('no version information'))
         # NOTE: tuple wrapping needed since eversion is itself a tuple
-        self.w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,))
+        w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,))
         for pkg in self.config.cubes():
             pkgversion = vcconf.get(pkg, _('no version information'))
-            self.w(u"<b>Package %s version:</b> %s<br/>\n" % (pkg, pkgversion))
-        self.w(u"</div>")
+            w(u"<b>Package %s version:</b> %s<br/>\n" % (pkg, pkgversion))
+        w(u"</div>")
         # creates a bug submission link if SUBMIT_URL is set
         submiturl = self.config['submit-url']
         if submiturl:
             binfo = text_error_description(ex, excinfo, req, eversion,
                                            [(pkg, vcconf.get(pkg, _('no version information')))
                                             for pkg in self.config.cubes()])
-            self.w(u'<form action="%s" method="post">\n' % html_escape(submiturl))
-            self.w(u'<fieldset>\n')
-            self.w(u'<textarea class="hidden" name="description">%s</textarea>' % html_escape(binfo))
-            self.w(u'<input type="hidden" name="description_format" value="text/rest"/>')
-            self.w(u'<input type="hidden" name="__bugreporting" value="1"/>')
-            self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report'))
-            self.w(u'</fieldset>\n')
-            self.w(u'</form>\n')
+            w(u'<form action="%s" method="post">\n' % html_escape(submiturl))
+            w(u'<fieldset>\n')
+            w(u'<textarea class="hidden" name="description">%s</textarea>' % html_escape(binfo))
+            w(u'<input type="hidden" name="description_format" value="text/rest"/>')
+            w(u'<input type="hidden" name="__bugreporting" value="1"/>')
+            w(u'<input type="submit" value="%s"/>' % _('Submit bug report'))
+            w(u'</fieldset>\n')
+            w(u'</form>\n')
         submitmail = self.config['submit-mail']
         if submitmail:
             binfo = text_error_description(ex, excinfo, req, eversion,
                                            [(pkg, vcconf.get(pkg, _('no version information')))
                                             for pkg in self.config.cubes()])
-            self.w(u'<form action="%s" method="post">\n' % req.build_url('reportbug'))
-            self.w(u'<fieldset>\n')
-            self.w(u'<input type="hidden" name="description" value="%s"/>' % html_escape(binfo))
-            self.w(u'<input type="hidden" name="__bugreporting" value="1"/>')
-            self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report by mail'))
-            self.w(u'</fieldset>\n')
-            self.w(u'</form>\n')
+            w(u'<form action="%s" method="post">\n' % req.build_url('reportbug'))
+            w(u'<fieldset>\n')
+            w(u'<input type="hidden" name="description" value="%s"/>' % html_escape(binfo))
+            w(u'<input type="hidden" name="__bugreporting" value="1"/>')
+            w(u'<input type="submit" value="%s"/>' % _('Submit bug report by mail'))
+            w(u'</fieldset>\n')
+            w(u'</form>\n')
 
 
 def exc_message(ex, encoding):
@@ -262,7 +261,7 @@
             return unicode(str(ex), encoding, 'replace')
         except:
             return unicode(repr(ex), encoding, 'replace')
-    
+
 def text_error_description(ex, excinfo, req, eversion, cubes):
     binfo = rest_traceback(excinfo, html_escape(ex))
     binfo += u'\n\n:URL: %s\n' % req.url()
@@ -284,23 +283,48 @@
 _('components')
 _('contentnavigation')
 
+
+def make_togglable_link(nodeid, label, cookiename):
+    """builds a HTML link that switches the visibility & remembers it"""
+    action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
+        (nodeid, cookiename)
+    return u'<a href="%s">%s</a>' % (action, label)
+
+def css_class(someclass):
+    return someclass and 'class="%s"' % someclass or ''
+
 class SystemEpropertiesForm(FormMixIn, StartupView):
     controller = 'edit'
     id = 'systemepropertiesform'
     title = _('site configuration')
     require_groups = ('managers',)
     category = 'startupview'
-    
+
     def linkable(self):
         return True
-    
+
     def url(self):
         """return the url associated with this view. We can omit rql here"""
         return self.build_url('view', vid=self.id)
-    
+
+    def _cookie_name(self, somestr):
+        return str('%s_property_%s' % (self.config.appid, somestr))
+
+    def _group_status(self, group, default=u'hidden'):
+        cookies = self.req.get_cookie()
+        cookiename = self._cookie_name(group)
+        cookie = cookies.get(cookiename)
+        if cookie is None:
+            cookies[cookiename] = default
+            self.req.set_cookie(cookies, cookiename, maxage=None)
+            status = default
+        else:
+            status = cookie.value
+        return status
+
     def call(self, **kwargs):
         """The default view representing the application's index"""
-        self.req.add_js('cubicweb.edition.js')
+        self.req.add_js(('cubicweb.edition.js', 'cubicweb.preferences.js'))
         self.req.add_css('cubicweb.preferences.css')
         vreg = self.vreg
         values = self.defined_keys
@@ -322,7 +346,7 @@
         for group, objects in groupedopts.items():
             for oid, keys in objects.items():
                 groupedopts[group][oid] = self.form(keys, True)
-        
+
         w = self.w
         req = self.req
         _ = req._
@@ -330,17 +354,21 @@
         w(self.error_message())
         for label, group, form in sorted((_(g), g, f)
                                          for g, f in mainopts.iteritems()):
+            status = css_class(self._group_status(group)) #'hidden' (collapsed), or '' (open) ?
             w(u'<h2 class="propertiesform">%s</h2>\n' %
-              (toggle_link('fieldset_' + group, label)))
-            w(u'<div id="fieldset_%s" class="hidden">' % group)
+              (make_togglable_link('fieldset_' + group, label,
+                                   self._cookie_name(group))))
+            w(u'<div id="fieldset_%s" %s>' % (group, status))
             w(u'<fieldset class="subentity">')
             w(form)
             w(u'</fieldset></div>')
         for label, group, objects in sorted((_(g), g, o)
                                             for g, o in groupedopts.iteritems()):
+            status = css_class(self._group_status(group))
             w(u'<h2 class="propertiesform">%s</h2>\n' %
-              (toggle_link('fieldset_' + group, label)))
-            w(u'<div id="fieldset_%s" class="hidden">' % group)
+              (make_togglable_link('fieldset_' + group, label,
+                                   self._cookie_name(group))))
+            w(u'<div id="fieldset_%s" %s>' % (group, status))
             for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
                                            for o, f in objects.iteritems()):
                 w(u'<fieldset class="subentity">')
@@ -352,21 +380,19 @@
                 w(form)
                 w(u'</fieldset>')
             w(u'</div>')
-            
-                
 
     @property
     @cached
     def eprops_rset(self):
         return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V, NOT P for_user U')
-    
+
     @property
     def defined_keys(self):
         values = {}
         for i, entity in enumerate(self.eprops_rset.entities()):
             values[entity.pkey] = i
         return values
-    
+
     def entity_for_key(self, key):
         values = self.defined_keys
         if key in values:
@@ -391,11 +417,11 @@
             w(u'<input type="hidden" name="__redirectparams" value="%s"/>\n'
               % html_escape(params))
         w(u'<input type="hidden" name="__redirectpath" value="%s"/>\n' % path)
-        #w(u'<input type="hidden" name="__redirectrql" value=""/>\n') 
+        #w(u'<input type="hidden" name="__redirectrql" value=""/>\n')
         w(u'<input type="hidden" name="__message" value="%s"/>\n'
           % self.req._('changes applied'))
         w(u'<table><tr><td>\n')
-       
+
         w(u'<table>\n')
         for key in keys:
             w(u'<tr>\n')
@@ -409,7 +435,7 @@
         w(u'</fieldset>\n')
         w(u'</form>\n')
         return stream.getvalue()
-        
+
     def form_row(self, w, key, splitlabel):
         entity = self.entity_for_key(key)
         eid = entity.eid
@@ -434,10 +460,10 @@
         w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('pkey', eid), key))
         w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('edits-pkey', eid), ''))
 
-        
+
 class EpropertiesForm(SystemEpropertiesForm):
     id = 'epropertiesform'
-    title = _('preferences')    
+    title = _('preferences')
     require_groups = ('users', 'managers') # we don't want guests to be able to come here
     __selectors__ = chainfirst(none_rset,
                                chainall(one_line_rset, accept_rset)),
@@ -449,7 +475,7 @@
             row = 0
         score = super(EpropertiesForm, cls).accept_rset(req, rset, row, col)
         # check current user is the rset user or he is in the managers group
-        if score and (req.user.eid == rset[row][col or 0] 
+        if score and (req.user.eid == rset[row][col or 0]
                       or req.user.matching_groups('managers')):
             return score
         return 0
@@ -459,7 +485,7 @@
         if self.rset is None:
             return self.req.user
         return self.rset.get_entity(self.row or 0, self.col or 0)
-    
+
     @property
     @cached
     def eprops_rset(self):
@@ -476,9 +502,9 @@
               % (eid_param('edits-for_user', eid), INTERNAL_FIELD_VALUE))
             w(u'<input type="hidden" name="%s" value="%s"/>'
               % (eid_param('for_user', eid), self.user.eid))
-    
-                   
-    
+
+
+
 
 class ProcessInformationView(StartupView):
     id = 'info'
--- a/web/views/navigation.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/navigation.py	Thu Feb 19 20:21:10 2009 +0100
@@ -36,15 +36,17 @@
         while start < rset.rowcount:
             stop = min(start + page_size - 1, rset.rowcount - 1)
             blocklist.append(self.page_link(basepath, params, start, stop,
-                                            u'%s - %s' % (start+1, stop+1)))
+                                            self.index_display(start, stop)))
             start = stop + 1
         w(u'<div class="pagination">')
         w(u'%s&nbsp;' % self.previous_link(params))
         w(u'[&nbsp;%s&nbsp;]' % u'&nbsp;| '.join(blocklist))
         w(u'&nbsp;%s' % self.next_link(params))
         w(u'</div>')
+        
+    def index_display(self, start, stop):
+        return u'%s - %s' % (start+1, stop+1)
 
-    
 class SortedNavigation(NavigationComponent):
     """sorted navigation apply if navigation is needed (according to page size)
     and if the result set is sorted
@@ -142,9 +144,11 @@
         self.w(u'</div>')
 
 
-def limit_rset_using_paged_nav(self, req, rset, w, forcedisplay=False, show_all_option=True):
+def limit_rset_using_paged_nav(self, req, rset, w, forcedisplay=False,
+                               show_all_option=True, page_size = None):
     showall = forcedisplay or req.form.get('__force_display') is not None
-    nav = not showall and self.vreg.select_component('navigation', req, rset)
+    nav = not showall and self.vreg.select_component('navigation', req, rset,
+                                                     page_size=page_size)
     if nav:
         # get boundaries before component rendering
         start, stop = nav.page_boundaries()
--- a/web/views/owl.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/owl.py	Thu Feb 19 20:21:10 2009 +0100
@@ -1,4 +1,4 @@
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import TransformError, xml_escape
 
 from cubicweb.common.view import StartupView
 from cubicweb.common.view import EntityView
@@ -11,124 +11,76 @@
                 '*': ''
                 }
 
-OWL_CARD_MAP_DATA = {'String': 'xsd:string',
-                     'Datetime': 'xsd:dateTime',
-                     'Bytes': 'xsd:byte',
-                     'Float': 'xsd:float',
-                     'Boolean': 'xsd:boolean',
-                     'Int': 'xsd:int',
-                     'Date':'xsd:date',
-                     'Time': 'xsd:time',
-                     'Password': 'xsd:byte',
-                     'Decimal' : 'xsd:decimal',
-                     'Interval': 'xsd:duration'
-                     }
+OWL_TYPE_MAP = {'String': 'xsd:string',
+                'Datetime': 'xsd:dateTime',
+                'Bytes': 'xsd:byte',
+                'Float': 'xsd:float',
+                'Boolean': 'xsd:boolean',
+                'Int': 'xsd:int',
+                'Date':'xsd:date',
+                'Time': 'xsd:time',
+                'Password': 'xsd:byte',
+                'Decimal' : 'xsd:decimal',
+                'Interval': 'xsd:duration'
+                }
 
 OWL_OPENING_ROOT = u'''<?xml version="1.0" encoding="UTF-8"?>
-        <!DOCTYPE rdf:RDF [
+<!DOCTYPE rdf:RDF [
         <!ENTITY owl "http://www.w3.org/2002/07/owl#" >
         <!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
-        <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" >
-        <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
-        <!ENTITY %s "http://logilab.org/owl/ontologies/%s#" >
-        
-        ]>        
-        <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-            xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
-            xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
-            xmlns:owl="http://www.w3.org/2002/07/owl#"
-            xmlns="http://logilab.org/owl/ontologies/%s#"
-            xmlns:%s="http://logilab.org/owl/ontologies/%s#"
-            xmlns:base="http://logilab.org/owl/ontologies/%s">
+]>        
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
+    xmlns:owl="http://www.w3.org/2002/07/owl#"
+    xmlns="http://logilab.org/owl/ontologies/%(appid)s#"
+    xmlns:%(appid)s="http://logilab.org/owl/ontologies/%(appid)s#"
+    xmlns:base="http://logilab.org/owl/ontologies/%(appid)s">
 
-    <owl:Ontology rdf:about="">
-        <rdfs:comment>
-        %s Cubicweb OWL Ontology                           
-                                        
-        </rdfs:comment>
-   </owl:Ontology>'''
+  <owl:Ontology rdf:about="">
+    <rdfs:comment>
+    %(appid)s Cubicweb OWL Ontology                           
+    </rdfs:comment>
+  </owl:Ontology>'''
 
 OWL_CLOSING_ROOT = u'</rdf:RDF>'
 
-class OWLView(StartupView):
-    """This view export in owl format the whole cubicweb ontologie. First part is the TBOX, second part is an ABOX ligth version."""
-    id = 'owl'
-    title = _('owl (tbox+abox)')
-    templatable =False
-    content_type = 'application/xml' # 'text/xml'
+DEFAULT_SKIP_RELS = frozenset(('is', 'is_instance_of', 'identity',
+                               'owned_by', 'created_by'))
 
-    def call(self):
-        
-        skipmeta = int(self.req.form.get('skipmeta', True))
-        self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name))
-        self.wview('tbox', None, writeprefix=False)
-        entities = [eschema for eschema in self.schema.entities()
-                    if not eschema.is_final()]
-        if skipmeta:
-            entities = [eschema for eschema in entities
-                        if not eschema.meta]
-        for entity in entities:
-            rql = 'Any X where X is %s'
-            rset = self.req.execute(rql% entity)
-            if rset:
-                self.wview('owlaboxlight', rset, writeprefix=False)
-        self.w(OWL_CLOSING_ROOT)
-
-class TBoxView(StartupView):
+class OWLView(StartupView):
     """This view export in owl format schema database. It is the TBOX"""
-    id = 'tbox'
-    title = _('tbox')
-    templatable =False
+    id = 'owl'
+    title = _('owl')
+    templatable = False
     content_type = 'application/xml' # 'text/xml'
 
     def call(self, writeprefix=True):
         skipmeta = int(self.req.form.get('skipmeta', True))
         if writeprefix:
-            self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name) )
-              
-        self.visit_schema(display_relations=True,
-                             skiprels=('is', 'is_instance_of', 'identity',
-                                       'owned_by', 'created_by'),
-                             skipmeta=skipmeta)
+            self.w(OWL_OPENING_ROOT % {'appid': self.schema.name})
+        self.visit_schema(skipmeta=skipmeta)
         if writeprefix:
             self.w(OWL_CLOSING_ROOT)
         
-    def visit_schema(self, display_relations=0,
-                     skiprels=(), skipmeta=True):
+    def visit_schema(self, skiprels=DEFAULT_SKIP_RELS, skipmeta=True):
         """get a layout for a whole schema"""
-        
-        entities = [eschema for eschema in self.schema.entities()
-                    if not eschema.is_final()]
+        entities = sorted([eschema for eschema in self.schema.entities()
+                           if not eschema.is_final()])
         if skipmeta:
             entities = [eschema for eschema in entities
                         if not eschema.meta]
-        keys = [(eschema.type, eschema) for eschema in entities]
         self.w(u'<!-- classes definition -->')
-        for key, eschema in sorted(keys):
+        for eschema in entities:
             self.visit_entityschema(eschema, skiprels)
-        self.w(u'<!-- property definition -->')
-        self.w(u'<!-- object property -->')
-        for key, eschema in sorted(keys):
-             self.visit_property_schema(eschema, skiprels)
-        self.w(u'<!-- datatype property -->')
-        for key, eschema in sorted(keys):
-            self.visit_property_object_schema(eschema, skiprels)
-         
-    def stereotype(self, name):
-        return Span((' <<%s>>' % name,), klass='stereotype')
-                       
+            self.w(u'<!-- property definition -->')
+            self.visit_property_schema(eschema, skiprels)
+            self.w(u'<!-- datatype property -->')
+            self.visit_property_object_schema(eschema)
+
     def visit_entityschema(self, eschema, skiprels=()):
         """get a layout for an entity OWL schema"""
-        etype = eschema.type
-        
-        if eschema.meta:
-            self.stereotype('meta')
-            self.w(u'''<owl:Class rdf:ID="%s"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
-                                '''%eschema, stereotype)
-        else:
-             self.w(u'''<owl:Class rdf:ID="%s"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
-                                '''% eschema)         
-       
+        self.w(u'<owl:Class rdf:ID="%s">'% eschema)         
         self.w(u'<!-- relations -->')    
         for rschema, targetschemas, role in eschema.relation_definitions():
             if rschema.type in skiprels:
@@ -141,13 +93,15 @@
                     card = rschema.rproperty(eschema, oeschema, 'cardinality')[0]
                 else:
                     card = rschema.rproperty(oeschema, eschema, 'cardinality')[1]
-                self.w(u'''<rdfs:subClassOf>
-                              <owl:Restriction>
-                              <owl:onProperty rdf:resource="#%s"/>
-                                %s
-                              </owl:Restriction>
-                           </rdfs:subClassOf>
-                                ''' % (label, OWL_CARD_MAP[card]))
+                cardtag = OWL_CARD_MAP[card]
+                if cardtag:
+                    self.w(u'''<rdfs:subClassOf>
+ <owl:Restriction>
+  <owl:onProperty rdf:resource="#%s"/>
+  %s
+ </owl:Restriction>
+</rdfs:subClassOf>
+''' % (label, cardtag))
 
         self.w(u'<!-- attributes -->')
               
@@ -157,21 +111,17 @@
             aname = rschema.type
             if aname == 'eid':
                 continue
-            card_data = aschema.type
             self.w(u'''<rdfs:subClassOf>
-                              <owl:Restriction>
-                                 <owl:onProperty rdf:resource="#%s"/>
-                                 <rdf:type rdf:resource="&owl;FunctionalProperty"/>
-                                 </owl:Restriction>
-                        </rdfs:subClassOf>'''
-                          
+  <owl:Restriction>
+   <owl:onProperty rdf:resource="#%s"/>
+   <rdf:type rdf:resource="&owl;FunctionalProperty"/>
+  </owl:Restriction>
+</rdfs:subClassOf>'''                         
                    % aname)
         self.w(u'</owl:Class>')
     
     def visit_property_schema(self, eschema, skiprels=()):
         """get a layout for property entity OWL schema"""
-        etype = eschema.type
-
         for rschema, targetschemas, role in eschema.relation_definitions():
             if rschema.type in skiprels:
                 continue
@@ -180,78 +130,53 @@
             for oeschema in targetschemas:
                 label = rschema.type
                 self.w(u'''<owl:ObjectProperty rdf:ID="%s">
-                              <rdfs:domain rdf:resource="#%s"/>
-                              <rdfs:range rdf:resource="#%s"/>
-                           </owl:ObjectProperty>                   
-                             
-                                ''' % (label, eschema, oeschema.type ))
+ <rdfs:domain rdf:resource="#%s"/>
+ <rdfs:range rdf:resource="#%s"/>
+</owl:ObjectProperty>                                                
+''' % (label, eschema, oeschema.type))
 
-    def visit_property_object_schema(self, eschema, skiprels=()):
-               
+    def visit_property_object_schema(self, eschema):
         for rschema, aschema in eschema.attribute_definitions():
             if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
                 continue
             aname = rschema.type
             if aname == 'eid':
                 continue
-            card_data = aschema.type
             self.w(u'''<owl:DatatypeProperty rdf:ID="%s">
-                          <rdfs:domain rdf:resource="#%s"/>
-                          <rdfs:range rdf:resource="%s"/>
-                       </owl:DatatypeProperty>'''
-                   % (aname, eschema, OWL_CARD_MAP_DATA[card_data]))
-            
-class OWLABOXLightView(EntityView):
-    '''This view represents the lihgt part of the ABOX for a given entity'''
-    id = 'owlaboxlight'
-    title = _('owlaboxlight')
-    templatable =False
-    accepts = ('Any',)
-    content_type = 'application/xml' # 'text/xml'
-    
-    def call(self, writeprefix=True):
+  <rdfs:domain rdf:resource="#%s"/>
+  <rdfs:range rdf:resource="%s"/>
+</owl:DatatypeProperty>'''
+                   % (aname, eschema, OWL_TYPE_MAP[aschema.type]))
 
-        skipmeta = int(self.req.form.get('skipmeta', True))
-        if writeprefix:
-            self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name))
-        for i in xrange(self.rset.rowcount):
-            self.cell_call(i, 0, skiprels=('is', 'is_instance_of', 'identity',
-                                       'owned_by', 'created_by'),
-                             skipmeta=skipmeta)
-        if writeprefix:
-            self.w(OWL_CLOSING_ROOT)
-        
-
-    def cell_call(self, row, col, skiprels=(), skipmeta=True):
-        entity = self.complete_entity(row, col)
-        eschema = entity.e_schema
-        self.w(u'<%s rdf:ID="%s">' % (eschema, entity.eid))
-        self.w(u'</%s>'% eschema)
-
-
-class OWLABOXEView(EntityView):
+            
+class OWLABOXView(EntityView):
     '''This view represents a part of the ABOX for a given entity.'''
     
     id = 'owlabox'
     title = _('owlabox')
-    templatable =False
+    templatable = False
     accepts = ('Any',)
     content_type = 'application/xml' # 'text/xml'
     
-    def call(self, writeprefix=True):
-
-        skipmeta = int(self.req.form.get('skipmeta', True))
-        if writeprefix:
-            self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name))
+    def call(self):
+        self.w(OWL_OPENING_ROOT % {'appid': self.schema.name})
         for i in xrange(self.rset.rowcount):
-            self.cell_call(i, 0, skiprels=('is', 'is_instance_of', 'identity',
-                                       'owned_by', 'created_by'),
-                             skipmeta=skipmeta)
-        if writeprefix:
-            self.w(OWL_CLOSING_ROOT)
+            self.cell_call(i, 0)
+        self.w(OWL_CLOSING_ROOT)
+
+    def cell_call(self, row, col, skiprels=DEFAULT_SKIP_RELS):
+        self.wview('owlaboxitem', self.rset, row=row, col=col, skiprels=skiprels)
+
         
+class OWLABOXItemView(EntityView):
+    '''This view represents a part of the ABOX for a given entity.'''
+    
+    id = 'owlaboxitem'
+    templatable = False
+    accepts = ('Any',)
+    content_type = 'application/xml' # 'text/xml'
 
-    def cell_call(self, row, col, skiprels=(), skipmeta=True):
+    def cell_call(self, row, col, skiprels=DEFAULT_SKIP_RELS):
         entity = self.complete_entity(row, col)
         eschema = entity.e_schema
         self.w(u'<%s rdf:ID="%s">' % (eschema, entity.eid))
@@ -264,9 +189,12 @@
             aname = rschema.type
             if aname == 'eid':
                 continue
-            attr = getattr(entity, aname)
-            if attr is not None:
-                self.w(u'<%s>%s</%s>' % (aname, html_escape(unicode(attr)), aname))
+            try:
+                attr = entity.printable_value(aname, format='text/plain')
+                if attr:
+                    self.w(u'<%s>%s</%s>' % (aname, xml_escape(attr), aname))
+            except TransformError:
+                pass
         self.w(u'<!--relations -->')
         for rschema, targetschemas, role in eschema.relation_definitions():
             if rschema.type in skiprels:
--- a/web/views/tabs.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/tabs.py	Thu Feb 19 20:21:10 2009 +0100
@@ -60,9 +60,13 @@
 
 class TabsMixin(LazyViewMixin):
 
+    @property
+    def cookie_name(self):
+        return str('%s_active_tab' % self.config.appid)
+
     def active_tab(self, tabs, default):
         cookie = self.req.get_cookie()
-        cookiename = '%s_active_tab' % self.config.appid
+        cookiename = self.cookie_name
         activetab = cookie.get(cookiename)
         if activetab is None:
             cookie[cookiename] = default
@@ -97,7 +101,7 @@
         for tab in tabs:
             w(u'<li>')
             w(u'<a href="#as-%s">' % tab)
-            w(u'<span onclick="set_tab(\'%s\')">' % tab)
+            w(u'<span onclick="set_tab(\'%s\', \'%s\')">' % (tab, self.cookie_name))
             w(self.req._(tab))
             w(u'</span>')
             w(u'</a>')
@@ -112,17 +116,11 @@
         # because the callback binding needs to be done before
         self.req.html_headers.add_onload(u"""
    jQuery('#entity-tabs > ul').tabs( { selected: %(tabindex)s });
-   set_tab('%(vid)s');
- """ % {'tabindex' : tabs.index(active_tab),
-        'vid'      : active_tab})
-
+   set_tab('%(vid)s', '%(cookiename)s');
+ """ % {'tabindex'   : tabs.index(active_tab),
+        'vid'        : active_tab,
+        'cookiename' : self.cookie_name})
 
-@monkeypatch(JSonController)
-def js_remember_active_tab(self, tabname):
-    cookie = self.req.get_cookie()
-    cookiename = '%s_active_tab' % self.config.appid
-    cookie[cookiename] = tabname
-    self.req.set_cookie(cookie, cookiename)
 
 class EntityRelatedTab(EntityView):
     """A view you should inherit from leftmost,
--- a/web/webctl.py	Thu Feb 19 20:19:05 2009 +0100
+++ b/web/webctl.py	Thu Feb 19 20:21:10 2009 +0100
@@ -2,12 +2,12 @@
 web configuration
 
 :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.toolsutils import CommandHandler
+from cubicweb.toolsutils import CommandHandler, confirm
 
 
 class WebCreateHandler(CommandHandler):
@@ -22,7 +22,10 @@
             print '** repository server configuration'
             print '-' * 72
             config.input_config('pyro-client', inputlevel)
-    
+        if confirm('allow anonymous access', False):
+           config.global_set_option('anonymous-user', 'anon') 
+           config.global_set_option('anonymous-password', 'anon') 
+        
     def postcreate(self):
         """hooks called once application's initialization has been completed"""