[schema view] the final touch. Things are getting nicely displayed, and code clean
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 14 Apr 2010 08:49:23 +0200
changeset 5239 471554b842d2
parent 5238 31c12863fd9d
child 5241 1460d69672bc
[schema view] the final touch. Things are getting nicely displayed, and code clean
entities/schemaobjs.py
i18n/en.po
i18n/es.po
i18n/fr.po
schemaviewer.py
web/schemaviewer.py
web/views/cwuser.py
web/views/emailaddress.py
web/views/primary.py
web/views/schema.py
web/views/tableview.py
web/views/workflow.py
--- a/entities/schemaobjs.py	Tue Apr 13 19:43:51 2010 +0200
+++ b/entities/schemaobjs.py	Wed Apr 14 08:49:23 2010 +0200
@@ -122,6 +122,9 @@
     def otype(self):
         return self.to_entity[0]
 
+    def yams_schema(self):
+        rschema = self._cw.vreg.schema.rschema(self.rtype.name)
+        return rschema.rdefs[(self.stype.name, self.otype.name)]
 
 class CWAttribute(CWRelation):
     __regid__ = 'CWAttribute'
--- a/i18n/en.po	Tue Apr 13 19:43:51 2010 +0200
+++ b/i18n/en.po	Wed Apr 14 08:49:23 2010 +0200
@@ -194,7 +194,7 @@
 msgid "Any"
 msgstr ""
 
-msgid "Attributes"
+msgid "Attributes permissions:"
 msgstr ""
 
 msgid "Attributes with non default permissions:"
@@ -510,9 +510,15 @@
 msgid "No result matching query"
 msgstr ""
 
+msgid "Non exhaustive list of views that may apply to entities of this type"
+msgstr ""
+
 msgid "OR"
 msgstr ""
 
+msgid "Parent classes:"
+msgstr ""
+
 msgid "Password"
 msgstr "Password"
 
@@ -592,6 +598,9 @@
 msgid "String_plural"
 msgstr "Strings"
 
+msgid "Sub-classes:"
+msgstr ""
+
 msgid "SubWorkflowExitPoint"
 msgstr "Subworkflow exit-point"
 
@@ -687,6 +696,9 @@
 msgid "This WorkflowTransition"
 msgstr "This workflow-transition"
 
+msgid "This entity type permissions:"
+msgstr ""
+
 msgid "Time"
 msgstr "Time"
 
@@ -788,9 +800,6 @@
 msgid "abstract base class for transitions"
 msgstr ""
 
-msgid "access type"
-msgstr ""
-
 msgid "action(s) on this selection"
 msgstr ""
 
@@ -1210,9 +1219,6 @@
 msgid "attribute"
 msgstr ""
 
-msgid "attributes permissions:"
-msgstr ""
-
 msgid "august"
 msgstr ""
 
@@ -1575,6 +1581,9 @@
 msgid "constraints applying on this relation"
 msgstr ""
 
+msgid "content type"
+msgstr ""
+
 msgid "contentnavigation"
 msgstr "contextual components"
 
@@ -1833,12 +1842,6 @@
 msgid "cwgroup-permissions"
 msgstr "permissions"
 
-msgid "cwrdef-description"
-msgstr "description"
-
-msgid "cwrdef-permissions"
-msgstr "permissions"
-
 msgid "cwrtype-description"
 msgstr "description"
 
@@ -2297,6 +2300,10 @@
 msgid "facets_in_state-facet_description"
 msgstr ""
 
+#, python-format
+msgid "failed to uniquify path (%s, %s)"
+msgstr ""
+
 msgid "february"
 msgstr ""
 
@@ -2399,9 +2406,6 @@
 msgid "full text or RQL query"
 msgstr ""
 
-msgid "fulltext indexed"
-msgstr ""
-
 msgid "fulltext_container"
 msgstr "fulltext container"
 
@@ -3017,6 +3021,9 @@
 msgid "opened web sessions"
 msgstr ""
 
+msgid "options"
+msgstr ""
+
 msgid "order"
 msgstr ""
 
@@ -3149,6 +3156,12 @@
 msgid "project"
 msgstr ""
 
+msgid "rdef-description"
+msgstr "description"
+
+msgid "rdef-permissions"
+msgstr "permissions"
+
 msgid "read"
 msgstr ""
 
@@ -3200,9 +3213,6 @@
 msgid "relation add"
 msgstr ""
 
-msgid "relation direction"
-msgstr ""
-
 msgid "relation removal"
 msgstr ""
 
@@ -3311,12 +3321,15 @@
 msgid "schema's permissions definitions"
 msgstr ""
 
-msgid "schema-description"
-msgstr "entity and relation types"
+msgid "schema-entity-types"
+msgstr ""
 
 msgid "schema-image"
 msgstr "image"
 
+msgid "schema-relation-types"
+msgstr ""
+
 msgid "schema-security"
 msgstr "permissions"
 
@@ -3968,15 +3981,18 @@
 msgid "view history"
 msgstr ""
 
+msgid "view identifier"
+msgstr ""
+
+msgid "view title"
+msgstr ""
+
 msgid "view workflow"
 msgstr ""
 
 msgid "view_index"
 msgstr "index"
 
-msgid "views"
-msgstr ""
-
 msgid "visible"
 msgstr ""
 
@@ -4074,3 +4090,6 @@
 
 msgid "you should probably delete that property"
 msgstr ""
+
+#~ msgid "schema-description"
+#~ msgstr "entity and relation types"
--- a/i18n/es.po	Tue Apr 13 19:43:51 2010 +0200
+++ b/i18n/es.po	Wed Apr 14 08:49:23 2010 +0200
@@ -202,8 +202,8 @@
 msgid "Any"
 msgstr "Cualquiera"
 
-msgid "Attributes"
-msgstr "Atributos"
+msgid "Attributes permissions:"
+msgstr ""
 
 msgid "Attributes with non default permissions:"
 msgstr ""
@@ -518,9 +518,15 @@
 msgid "No result matching query"
 msgstr "Ningún resultado corresponde a su búsqueda"
 
+msgid "Non exhaustive list of views that may apply to entities of this type"
+msgstr ""
+
 msgid "OR"
 msgstr "O"
 
+msgid "Parent classes:"
+msgstr ""
+
 msgid "Password"
 msgstr "Contraseña"
 
@@ -600,6 +606,9 @@
 msgid "String_plural"
 msgstr "Cadenas de caracteres"
 
+msgid "Sub-classes:"
+msgstr ""
+
 msgid "SubWorkflowExitPoint"
 msgstr ""
 
@@ -695,6 +704,9 @@
 msgid "This WorkflowTransition"
 msgstr ""
 
+msgid "This entity type permissions:"
+msgstr ""
+
 msgid "Time"
 msgstr "Hora"
 
@@ -811,9 +823,6 @@
 msgid "abstract base class for transitions"
 msgstr ""
 
-msgid "access type"
-msgstr "Tipo de Acceso"
-
 msgid "action(s) on this selection"
 msgstr "acción(es) en esta selección"
 
@@ -1235,9 +1244,6 @@
 msgid "attribute"
 msgstr "Atributo"
 
-msgid "attributes permissions:"
-msgstr ""
-
 msgid "august"
 msgstr "Agosto"
 
@@ -1606,6 +1612,9 @@
 msgid "constraints applying on this relation"
 msgstr "Restricciones que se aplican a esta relación"
 
+msgid "content type"
+msgstr ""
+
 msgid "contentnavigation"
 msgstr "Componentes contextuales"
 
@@ -1874,12 +1883,6 @@
 msgid "cwgroup-permissions"
 msgstr ""
 
-msgid "cwrdef-description"
-msgstr ""
-
-msgid "cwrdef-permissions"
-msgstr ""
-
 msgid "cwrtype-description"
 msgstr ""
 
@@ -2347,6 +2350,10 @@
 msgid "facets_in_state-facet_description"
 msgstr "faceta en el estado"
 
+#, python-format
+msgid "failed to uniquify path (%s, %s)"
+msgstr ""
+
 msgid "february"
 msgstr "Febrero"
 
@@ -2449,9 +2456,6 @@
 msgid "full text or RQL query"
 msgstr "Texto de búsqueda o demanda RQL"
 
-msgid "fulltext indexed"
-msgstr ""
-
 msgid "fulltext_container"
 msgstr "Contenedor de texto indexado"
 
@@ -3091,6 +3095,9 @@
 msgid "opened web sessions"
 msgstr ""
 
+msgid "options"
+msgstr ""
+
 msgid "order"
 msgstr "orden"
 
@@ -3222,6 +3229,12 @@
 msgid "project"
 msgstr "Proyecto"
 
+msgid "rdef-description"
+msgstr ""
+
+msgid "rdef-permissions"
+msgstr ""
+
 msgid "read"
 msgstr "Lectura"
 
@@ -3273,9 +3286,6 @@
 msgid "relation add"
 msgstr ""
 
-msgid "relation direction"
-msgstr ""
-
 msgid "relation removal"
 msgstr ""
 
@@ -3388,12 +3398,15 @@
 msgid "schema's permissions definitions"
 msgstr "definiciones de permisos del esquema"
 
-msgid "schema-description"
+msgid "schema-entity-types"
 msgstr ""
 
 msgid "schema-image"
 msgstr "esquema imagen"
 
+msgid "schema-relation-types"
+msgstr ""
+
 msgid "schema-security"
 msgstr ""
 
@@ -4055,15 +4068,18 @@
 msgid "view history"
 msgstr ""
 
+msgid "view identifier"
+msgstr ""
+
+msgid "view title"
+msgstr ""
+
 msgid "view workflow"
 msgstr "ver workflow"
 
 msgid "view_index"
 msgstr ""
 
-msgid "views"
-msgstr "vistas"
-
 msgid "visible"
 msgstr "visible"
 
@@ -4171,6 +4187,9 @@
 #~ msgid "Application"
 #~ msgstr "Aplicación"
 
+#~ msgid "Attributes"
+#~ msgstr "Atributos"
+
 #~ msgid "Debug level set to %s"
 #~ msgstr "Nivel de debug puesto a %s"
 
@@ -4202,6 +4221,9 @@
 #~ msgid "__msg state changed"
 #~ msgstr "El estado a cambiado"
 
+#~ msgid "access type"
+#~ msgstr "Tipo de Acceso"
+
 #~ msgid "account state"
 #~ msgstr "Estado de la Cuenta"
 
@@ -4502,6 +4524,9 @@
 #~ "usuario para el cual aplica esta propiedad. Si no se establece esta "
 #~ "relación, la propiedad es considerada como una propiedad global."
 
+#~ msgid "views"
+#~ msgstr "vistas"
+
 #~ msgid ""
 #~ "when multiple addresses are equivalent (such as python-projects@logilab."
 #~ "org and python-projects@lists.logilab.org), set this to true on one of "
--- a/i18n/fr.po	Tue Apr 13 19:43:51 2010 +0200
+++ b/i18n/fr.po	Wed Apr 14 08:49:23 2010 +0200
@@ -201,8 +201,8 @@
 msgid "Any"
 msgstr "N'importe"
 
-msgid "Attributes"
-msgstr "Attributs"
+msgid "Attributes permissions:"
+msgstr "Permissions des attributs"
 
 msgid "Attributes with non default permissions:"
 msgstr "Attributs ayant des permissions non-standard"
@@ -529,9 +529,15 @@
 msgid "No result matching query"
 msgstr "aucun résultat"
 
+msgid "Non exhaustive list of views that may apply to entities of this type"
+msgstr "Liste non exhausite des vues s'appliquant à ce type d'entité"
+
 msgid "OR"
 msgstr "OU"
 
+msgid "Parent classes:"
+msgstr "Classes parentes :"
+
 msgid "Password"
 msgstr "Mot de passe"
 
@@ -611,6 +617,9 @@
 msgid "String_plural"
 msgstr "Chaînes de caractères"
 
+msgid "Sub-classes:"
+msgstr "Classes filles :"
+
 msgid "SubWorkflowExitPoint"
 msgstr "Sortie de sous-workflow"
 
@@ -706,6 +715,9 @@
 msgid "This WorkflowTransition"
 msgstr "Cette transition workflow"
 
+msgid "This entity type permissions:"
+msgstr "Permissions pour ce type d'endité"
+
 msgid "Time"
 msgstr "Heure"
 
@@ -828,9 +840,6 @@
 msgid "abstract base class for transitions"
 msgstr "classe de base abstraite pour les transitions"
 
-msgid "access type"
-msgstr "type d'accès"
-
 msgid "action(s) on this selection"
 msgstr "action(s) sur cette sélection"
 
@@ -1254,9 +1263,6 @@
 msgid "attribute"
 msgstr "attribut"
 
-msgid "attributes permissions:"
-msgstr "permissions des attributs :"
-
 msgid "august"
 msgstr "août"
 
@@ -1626,6 +1632,9 @@
 msgid "constraints applying on this relation"
 msgstr "contraintes s'appliquant à cette relation"
 
+msgid "content type"
+msgstr "type MIME"
+
 msgid "contentnavigation"
 msgstr "composants contextuels"
 
@@ -1897,12 +1906,6 @@
 msgid "cwgroup-permissions"
 msgstr "permissions"
 
-msgid "cwrdef-description"
-msgstr "description"
-
-msgid "cwrdef-permissions"
-msgstr "permissions"
-
 msgid "cwrtype-description"
 msgstr "description"
 
@@ -2381,6 +2384,10 @@
 msgid "facets_in_state-facet_description"
 msgstr ""
 
+#, python-format
+msgid "failed to uniquify path (%s, %s)"
+msgstr ""
+
 msgid "february"
 msgstr "février"
 
@@ -2483,9 +2490,6 @@
 msgid "full text or RQL query"
 msgstr "texte à rechercher ou requête RQL"
 
-msgid "fulltext indexed"
-msgstr "indexation du texte"
-
 msgid "fulltext_container"
 msgstr "conteneur du texte indexé"
 
@@ -3125,6 +3129,9 @@
 msgid "opened web sessions"
 msgstr "sessions web ouvertes"
 
+msgid "options"
+msgstr "options"
+
 msgid "order"
 msgstr "ordre"
 
@@ -3258,6 +3265,12 @@
 msgid "project"
 msgstr "projet"
 
+msgid "rdef-description"
+msgstr "description"
+
+msgid "rdef-permissions"
+msgstr "permissions"
+
 msgid "read"
 msgstr "lecture"
 
@@ -3309,9 +3322,6 @@
 msgid "relation add"
 msgstr "ajout de relation"
 
-msgid "relation direction"
-msgstr "sens de la relation"
-
 msgid "relation removal"
 msgstr "suppression de relation"
 
@@ -3425,12 +3435,15 @@
 msgid "schema's permissions definitions"
 msgstr "permissions définies dans le schéma"
 
-msgid "schema-description"
-msgstr "types d'entité et de relation"
+msgid "schema-entity-types"
+msgstr "types d'entités"
 
 msgid "schema-image"
 msgstr "image"
 
+msgid "schema-relation-types"
+msgstr "types de relations"
+
 msgid "schema-security"
 msgstr "permissions"
 
@@ -4098,15 +4111,18 @@
 msgid "view history"
 msgstr "voir l'historique"
 
+msgid "view identifier"
+msgstr "identifiant"
+
+msgid "view title"
+msgstr "titre"
+
 msgid "view workflow"
 msgstr "voir les états possibles"
 
 msgid "view_index"
 msgstr "accueil"
 
-msgid "views"
-msgstr "vues"
-
 msgid "visible"
 msgstr "visible"
 
--- a/schemaviewer.py	Tue Apr 13 19:43:51 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,209 +0,0 @@
-"""an helper class to display CubicWeb schema using ureports
-
-:organization: Logilab
-:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
-"""
-__docformat__ = "restructuredtext en"
-_ = unicode
-
-from logilab.common.ureports import Section, Title, Table, Link, Span, Text
-
-from yams.schema2dot import CARD_MAP
-from yams.schema import RelationDefinitionSchema
-
-I18NSTRINGS = [_('read'), _('add'), _('delete'), _('update'), _('order')]
-
-
-class SchemaViewer(object):
-    """return an ureport layout for some part of a schema"""
-    def __init__(self, req=None, encoding=None):
-        self.req = req
-        if req is not None:
-            self.req.add_css('cubicweb.schema.css')
-            if not encoding:
-                encoding = req.encoding
-        self.encoding = encoding
-
-    def format_acls(self, schema, access_types):
-        """return a layout displaying access control lists"""
-        data = [self.req._('access type'), self.req._('groups')]
-        for access_type in access_types:
-            data.append(self.req._(access_type))
-            acls = [Link(self.req.build_url('cwgroup/%s' % group), self.req._(group))
-                    for group in schema.get_groups(access_type)]
-            acls += (Text(rqlexp.expression) for rqlexp in schema.get_rqlexprs(access_type))
-            acls = [n for _n in acls for n in (_n, Text(', '))][:-1]
-            data.append(Span(children=acls))
-        return Section(children=(Table(cols=2, cheaders=1, rheaders=1, children=data),),
-                       klass='acl')
-
-    def visit_schema(self, schema, display_relations=0, skiptypes=()):
-        """get a layout for a whole schema"""
-        title = Title(self.req._('Schema %s') % schema.name,
-                      klass='titleUnderline')
-        layout = Section(children=(title,))
-        esection = Section(children=(Title(self.req._('Entities'),
-                                           klass='titleUnderline'),))
-        layout.append(esection)
-        eschemas = [eschema for eschema in schema.entities()
-                    if not (eschema.final or eschema in skiptypes)]
-        for eschema in sorted(eschemas):
-            esection.append(self.visit_entityschema(eschema, skiptypes))
-        if display_relations:
-            title = Title(self.req._('Relations'), klass='titleUnderline')
-            rsection = Section(children=(title,))
-            layout.append(rsection)
-            relations = [rschema for rschema in schema.relations()
-                         if not (rschema.final or rschema.type in skiptypes)]
-            keys = [(rschema.type, rschema) for rschema in relations]
-            for key, rschema in sorted(keys):
-                relstr = self.visit_relationschema(rschema)
-                rsection.append(relstr)
-        return layout
-
-    def _entity_attributes_data(self, eschema):
-        _ = self.req._
-        data = [_('attribute'), _('type'), _('default'), _('constraints')]
-        for rschema, aschema in eschema.attribute_definitions():
-            rdef = eschema.rdef(rschema)
-            if not rdef.may_have_permission('read', self.req):
-                continue
-            aname = rschema.type
-            if aname == 'eid':
-                continue
-            data.append('%s (%s)' % (aname, _(aname)))
-            data.append(_(aschema.type))
-            defaultval = eschema.default(aname)
-            if defaultval is not None:
-                default = self.to_string(defaultval)
-            elif rdef.cardinality[0] == '1':
-                default = _('required field')
-            else:
-                default = ''
-            data.append(default)
-            constraints = rschema.rproperty(eschema.type, aschema.type,
-                                            'constraints')
-            data.append(', '.join(str(constr) for constr in constraints))
-        return data
-
-    def eschema_link_url(self, eschema):
-        return self.req.build_url('cwetype/%s' % eschema)
-
-    def rschema_link_url(self, rschema):
-        return self.req.build_url('cwrtype/%s' % rschema)
-
-    def stereotype(self, name):
-        return Span((' <<%s>>' % name,), klass='stereotype')
-
-    def visit_entityschema(self, eschema, skiptypes=()):
-        """get a layout for an entity schema"""
-        etype = eschema.type
-        layout = Section(children=' ', klass='clear')
-        layout.append(Link(etype,'&#160;' , id=etype)) # anchor
-        title = Link(self.eschema_link_url(eschema), etype)
-        boxchild = [Section(children=(title, ' (%s)'% eschema.display_name(self.req)), klass='title')]
-        data = []
-        data.append(Section(children=boxchild, klass='box'))
-        data.append(Section(children='', klass='vl'))
-        data.append(Section(children='', klass='hl'))
-        t_vars = []
-        rels = []
-        first = True
-        for rschema, targetschemas, role in eschema.relation_definitions():
-            if rschema.type in skiptypes:
-                continue
-            rschemaurl = self.rschema_link_url(rschema)
-            for oeschema in targetschemas:
-                rdef = rschema.role_rdef(eschema, oeschema, role)
-                if not rdef.may_have_permission('read', self.req):
-                    continue
-                label = rschema.type
-                if role == 'subject':
-                    cards = rschema.rproperty(eschema, oeschema, 'cardinality')
-                else:
-                    cards = rschema.rproperty(oeschema, eschema, 'cardinality')
-                    cards = cards[::-1]
-                label = '%s %s (%s) %s' % (CARD_MAP[cards[1]], label,
-                                           display_name(self.req, label, role),
-                                           CARD_MAP[cards[0]])
-                rlink = Link(rschemaurl, label)
-                elink = Link(self.eschema_link_url(oeschema), oeschema.type)
-                if first:
-                    t_vars.append(Section(children=(elink,), klass='firstvar'))
-                    rels.append(Section(children=(rlink,), klass='firstrel'))
-                    first = False
-                else:
-                    t_vars.append(Section(children=(elink,), klass='var'))
-                    rels.append(Section(children=(rlink,), klass='rel'))
-        data.append(Section(children=rels, klass='rels'))
-        data.append(Section(children=t_vars, klass='vars'))
-        layout.append(Section(children=data, klass='entityAttributes'))
-        return layout
-
-    def visit_relationschema(self, rschema, title=True):
-        """get a layout for a relation schema"""
-        _ = self.req._
-        if title:
-            title = Link(self.rschema_link_url(rschema), rschema.type)
-            stereotypes = []
-            if rschema.meta:
-                stereotypes.append('meta')
-            if rschema.symmetric:
-                stereotypes.append('symmetric')
-            if rschema.inlined:
-                stereotypes.append('inlined')
-            title = Section(children=(title, ' (%s)'%rschema.display_name(self.req)), klass='title')
-            if stereotypes:
-                title.append(self.stereotype(','.join(stereotypes)))
-            layout = Section(children=(title,), klass='schema')
-        else:
-            layout = Section(klass='schema')
-        data = [_('from'), _('to')]
-        schema = rschema.schema
-        rschema_objects = rschema.objects()
-        if rschema_objects:
-            # might be empty
-            properties = [p for p in RelationDefinitionSchema.rproperty_defs(rschema_objects[0])
-                          if not p in ('cardinality', 'composite', 'eid')]
-        else:
-            properties = []
-        data += [_(prop) for prop in properties]
-        cols = len(data)
-        done = set()
-        for subjtype, objtypes in rschema.associations():
-            for objtype in objtypes:
-                if (subjtype, objtype) in done:
-                    continue
-                done.add((subjtype, objtype))
-                if rschema.symmetric:
-                    done.add((objtype, subjtype))
-                data.append(Link(self.eschema_link_url(schema[subjtype]), subjtype))
-                data.append(Link(self.eschema_link_url(schema[objtype]), objtype))
-                rdef = rschema.rdef(subjtype, objtype)
-                for prop in properties:
-                    val = getattr(rdef, prop)
-                    if val is None:
-                        val = ''
-                    elif prop == 'constraints':
-                        val = ', '.join([c.restriction for c in val])
-                    elif isinstance(val, (list, tuple)):
-                        val = ', '.join(str(v) for v in val)
-                    elif val and isinstance(val, basestring):
-                        val = _(val)
-                    else:
-                        val = str(val)
-                    data.append(Text(val))
-        table = Table(cols=cols, rheaders=1, children=data, klass='listing')
-        layout.append(Section(children=(table,), klass='relationDefinition'))
-        #if self.req.user.matching_groups('managers'):
-        #    layout.append(self.format_acls(rschema, ('read', 'add', 'delete')))
-        layout.append(Section(children='', klass='clear'))
-        return layout
-
-    def to_string(self, value):
-        """used to converte arbitrary values to encoded string"""
-        if isinstance(value, unicode):
-            return value.encode(self.encoding, 'replace')
-        return str(value)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/schemaviewer.py	Wed Apr 14 08:49:23 2010 +0200
@@ -0,0 +1,193 @@
+"""an helper class to display CubicWeb schema using ureports
+
+:organization: Logilab
+:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
+"""
+__docformat__ = "restructuredtext en"
+_ = unicode
+
+from logilab.common.ureports import Section, Title, Table, Link, Span, Text
+
+from yams.schema2dot import CARD_MAP
+from yams.schema import RelationDefinitionSchema
+
+I18NSTRINGS = [_('read'), _('add'), _('delete'), _('update'), _('order')]
+
+
+class SchemaViewer(object):
+    """return an ureport layout for some part of a schema"""
+    def __init__(self, req=None, encoding=None):
+        self.req = req
+        if req is not None:
+            self.req.add_css('cubicweb.schema.css')
+            if not encoding:
+                encoding = req.encoding
+        self.encoding = encoding
+
+    def visit_schema(self, schema, display_relations=0, skiptypes=()):
+        """get a layout for a whole schema"""
+        title = Title(self.req._('Schema %s') % schema.name,
+                      klass='titleUnderline')
+        layout = Section(children=(title,))
+        esection = Section(children=(Title(self.req._('Entities'),
+                                           klass='titleUnderline'),))
+        layout.append(esection)
+        eschemas = [eschema for eschema in schema.entities()
+                    if not (eschema.final or eschema in skiptypes)]
+        for eschema in sorted(eschemas):
+            esection.append(self.visit_entityschema(eschema, skiptypes))
+        if display_relations:
+            title = Title(self.req._('Relations'), klass='titleUnderline')
+            rsection = Section(children=(title,))
+            layout.append(rsection)
+            relations = [rschema for rschema in schema.relations()
+                         if not (rschema.final or rschema.type in skiptypes)]
+            keys = [(rschema.type, rschema) for rschema in relations]
+            for key, rschema in sorted(keys):
+                relstr = self.visit_relationschema(rschema)
+                rsection.append(relstr)
+        return layout
+
+    def _entity_attributes_data(self, eschema):
+        _ = self.req._
+        data = [_('attribute'), _('type'), _('default'), _('constraints')]
+        for rschema, aschema in eschema.attribute_definitions():
+            rdef = eschema.rdef(rschema)
+            if not rdef.may_have_permission('read', self.req):
+                continue
+            aname = rschema.type
+            if aname == 'eid':
+                continue
+            data.append('%s (%s)' % (aname, _(aname)))
+            data.append(_(aschema.type))
+            defaultval = eschema.default(aname)
+            if defaultval is not None:
+                default = self.to_string(defaultval)
+            elif rdef.cardinality[0] == '1':
+                default = _('required field')
+            else:
+                default = ''
+            data.append(default)
+            constraints = rschema.rproperty(eschema.type, aschema.type,
+                                            'constraints')
+            data.append(', '.join(str(constr) for constr in constraints))
+        return data
+
+    def eschema_link_url(self, eschema):
+        return self.req.build_url('cwetype/%s' % eschema)
+
+    def rschema_link_url(self, rschema):
+        return self.req.build_url('cwrtype/%s' % rschema)
+
+    def stereotype(self, name):
+        return Span((' <<%s>>' % name,), klass='stereotype')
+
+    def visit_entityschema(self, eschema, skiptypes=()):
+        """get a layout for an entity schema"""
+        etype = eschema.type
+        layout = Section(children=' ', klass='clear')
+        layout.append(Link(etype,'&#160;' , id=etype)) # anchor
+        title = Link(self.eschema_link_url(eschema), etype)
+        boxchild = [Section(children=(title,), klass='title')]
+        data = []
+        data.append(Section(children=boxchild, klass='box'))
+        data.append(Section(children='', klass='vl'))
+        data.append(Section(children='', klass='hl'))
+        t_vars = []
+        rels = []
+        first = True
+        for rschema, targetschemas, role in eschema.relation_definitions():
+            if rschema.type in skiptypes:
+                continue
+            rschemaurl = self.rschema_link_url(rschema)
+            for oeschema in targetschemas:
+                rdef = rschema.role_rdef(eschema, oeschema, role)
+                if not rdef.may_have_permission('read', self.req):
+                    continue
+                label = rschema.type
+                if role == 'subject':
+                    cards = rschema.rproperty(eschema, oeschema, 'cardinality')
+                else:
+                    cards = rschema.rproperty(oeschema, eschema, 'cardinality')
+                    cards = cards[::-1]
+                label = '%s %s %s' % (CARD_MAP[cards[1]], label,
+                                      CARD_MAP[cards[0]])
+                rlink = Link(rschemaurl, label)
+                elink = Link(self.eschema_link_url(oeschema), oeschema.type)
+                if first:
+                    t_vars.append(Section(children=(elink,), klass='firstvar'))
+                    rels.append(Section(children=(rlink,), klass='firstrel'))
+                    first = False
+                else:
+                    t_vars.append(Section(children=(elink,), klass='var'))
+                    rels.append(Section(children=(rlink,), klass='rel'))
+        data.append(Section(children=rels, klass='rels'))
+        data.append(Section(children=t_vars, klass='vars'))
+        layout.append(Section(children=data, klass='entityAttributes'))
+        return layout
+
+    def visit_relationschema(self, rschema, title=True):
+        """get a layout for a relation schema"""
+        _ = self.req._
+        if title:
+            title = Link(self.rschema_link_url(rschema), rschema.type)
+            stereotypes = []
+            if rschema.meta:
+                stereotypes.append('meta')
+            if rschema.symmetric:
+                stereotypes.append('symmetric')
+            if rschema.inlined:
+                stereotypes.append('inlined')
+            title = Section(children=(title, ' (%s)'%rschema.display_name(self.req)), klass='title')
+            if stereotypes:
+                title.append(self.stereotype(','.join(stereotypes)))
+            layout = Section(children=(title,), klass='schema')
+        else:
+            layout = Section(klass='schema')
+        data = [_('from'), _('to')]
+        schema = rschema.schema
+        rschema_objects = rschema.objects()
+        if rschema_objects:
+            # might be empty
+            properties = [p for p in RelationDefinitionSchema.rproperty_defs(rschema_objects[0])
+                          if not p in ('cardinality', 'composite', 'eid')]
+        else:
+            properties = []
+        data += [_(prop) for prop in properties]
+        cols = len(data)
+        done = set()
+        for subjtype, objtypes in rschema.associations():
+            for objtype in objtypes:
+                if (subjtype, objtype) in done:
+                    continue
+                done.add((subjtype, objtype))
+                if rschema.symmetric:
+                    done.add((objtype, subjtype))
+                data.append(Link(self.eschema_link_url(schema[subjtype]), subjtype))
+                data.append(Link(self.eschema_link_url(schema[objtype]), objtype))
+                rdef = rschema.rdef(subjtype, objtype)
+                for prop in properties:
+                    val = getattr(rdef, prop)
+                    if val is None:
+                        val = ''
+                    elif prop == 'constraints':
+                        val = ', '.join([c.restriction for c in val])
+                    elif isinstance(val, (list, tuple)):
+                        val = ', '.join(str(v) for v in val)
+                    elif val and isinstance(val, basestring):
+                        val = _(val)
+                    else:
+                        val = str(val)
+                    data.append(Text(val))
+        table = Table(cols=cols, rheaders=1, children=data, klass='listing')
+        layout.append(Section(children=(table,), klass='relationDefinition'))
+        layout.append(Section(children='', klass='clear'))
+        return layout
+
+    def to_string(self, value):
+        """used to converte arbitrary values to encoded string"""
+        if isinstance(value, unicode):
+            return value.encode(self.encoding, 'replace')
+        return str(value)
--- a/web/views/cwuser.py	Tue Apr 13 19:43:51 2010 +0200
+++ b/web/views/cwuser.py	Wed Apr 14 08:49:23 2010 +0200
@@ -90,7 +90,7 @@
     __regid__ = 'cwgroup-main'
     __select__ = tabs.PrimaryTab.__select__ & implements('CWGroup')
 
-    def render_entity_attributes(self, entity, siderelations=None):
+    def render_entity_attributes(self, entity):
         rql = 'Any U, FN, LN, CD, LL ORDERBY L WHERE U in_group G, ' \
               'U login L, U firstname FN, U surname LN, U creation_date CD, ' \
               'U last_login_time LL, G eid %(x)s'
--- a/web/views/emailaddress.py	Tue Apr 13 19:43:51 2010 +0200
+++ b/web/views/emailaddress.py	Wed Apr 14 08:49:23 2010 +0200
@@ -12,8 +12,13 @@
 from cubicweb.schema import display_name
 from cubicweb.selectors import implements
 from cubicweb import Unauthorized
+from cubicweb.web import uicfg
 from cubicweb.web.views import baseviews, primary
 
+_pvs = uicfg.primaryview_section
+_pvs.tag_subject_of(('*', 'use_email', '*'), 'attributes')
+_pvs.tag_subject_of(('*', 'primary_email', '*'), 'hidden')
+
 class EmailAddressPrimaryView(primary.PrimaryView):
     __select__ = implements('EmailAddress')
 
--- a/web/views/primary.py	Tue Apr 13 19:43:51 2010 +0200
+++ b/web/views/primary.py	Wed Apr 14 08:49:23 2010 +0200
@@ -113,7 +113,7 @@
         """default implementation return an empty string"""
         return u''
 
-    def render_entity_attributes(self, entity, siderelations=None):
+    def render_entity_attributes(self, entity):
         display_attributes = []
         for rschema, _, role, dispctrl in self._section_def(entity, 'attributes'):
             vid = dispctrl.get('vid', 'reledit')
@@ -139,7 +139,7 @@
                     self._render_attribute(rschema, value, role=role, table=True)
             self.w(u'</table>')
 
-    def render_entity_relations(self, entity, siderelations=None):
+    def render_entity_relations(self, entity):
         for rschema, tschemas, role, dispctrl in self._section_def(entity, 'relations'):
             rset = self._relation_rset(entity, rschema, role, dispctrl)
             if rset:
@@ -297,18 +297,7 @@
 
 _pvs = uicfg.primaryview_section
 for rtype in ('eid', 'creation_date', 'modification_date', 'cwuri',
-              'is', 'is_instance_of', 'identity',
-              'owned_by', 'created_by', 'in_state',
-              'wf_info_for', 'by_transition', 'from_state', 'to_state',
-              'require_permission', 'from_entity', 'to_entity',
-              'see_also'):
+              'is', 'is_instance_of', 'identity', 'owned_by', 'created_by',
+              'require_permission', 'see_also'):
     _pvs.tag_subject_of(('*', rtype, '*'), 'hidden')
     _pvs.tag_object_of(('*', rtype, '*'), 'hidden')
-
-_pvs.tag_subject_of(('*', 'use_email', '*'), 'attributes')
-_pvs.tag_subject_of(('*', 'primary_email', '*'), 'hidden')
-
-for attr in ('name', 'final'):
-    _pvs.tag_attribute(('CWEType', attr), 'hidden')
-for attr in ('name', 'final', 'symmetric', 'inlined'):
-    _pvs.tag_attribute(('CWRType', attr), 'hidden')
--- a/web/views/schema.py	Tue Apr 13 19:43:51 2010 +0200
+++ b/web/views/schema.py	Wed Apr 14 08:49:23 2010 +0200
@@ -18,10 +18,9 @@
                                 has_related_entities, authenticated_user)
 from cubicweb.schema import (META_RTYPES, SCHEMA_TYPES, SYSTEM_RTYPES,
                              WORKFLOW_TYPES, INTERNAL_TYPES)
-from cubicweb.schemaviewer import SchemaViewer
 from cubicweb.view import EntityView, StartupView
 from cubicweb import tags, uilib
-from cubicweb.web import action, facet, uicfg
+from cubicweb.web import action, facet, uicfg, schemaviewer
 from cubicweb.web.views import TmpFileViewMixin
 from cubicweb.web.views import primary, baseviews, tabs, tableview, iprogress
 
@@ -36,15 +35,32 @@
     return ALWAYS_SKIP_TYPES
 
 _pvs = uicfg.primaryview_section
+_pvdc = uicfg.primaryview_display_ctrl
+
 for _action in ('read', 'add', 'update', 'delete'):
     _pvs.tag_subject_of(('*', '%s_permission' % _action, '*'), 'hidden')
     _pvs.tag_object_of(('*', '%s_permission' % _action, '*'), 'hidden')
 
-_pvs.tag_object_of(('Workflow', 'workflow_of', 'CWEType'), 'hidden')
-_pvs.tag_subject_of(('CWEType', 'default_workflow', 'Workflow'), 'hidden')
+for _etype in ('CWEType', 'CWRType', 'CWAttribute', 'CWRelation'):
+    _pvdc.tag_attribute((_etype, 'description'), {'showlabel': False})
 
+_pvs.tag_attribute(('CWEType', 'name'), 'hidden')
+_pvs.tag_attribute(('CWEType', 'final'), 'hidden')
+_pvs.tag_object_of(('*', 'workflow_of', 'CWEType'), 'hidden')
+_pvs.tag_subject_of(('CWEType', 'default_workflow', '*'), 'hidden')
+_pvs.tag_object_of(('*', 'specializes', 'CWEType'), 'hidden')
+_pvs.tag_subject_of(('CWEType', 'specializes', '*'), 'hidden')
+_pvs.tag_object_of(('*', 'from_entity', 'CWEType'), 'hidden')
+_pvs.tag_object_of(('*', 'to_entity', 'CWEType'), 'hidden')
+
+_pvs.tag_attribute(('CWRType', 'name'), 'hidden')
+_pvs.tag_attribute(('CWRType', 'final'), 'hidden')
 _pvs.tag_object_of(('*', 'relation_type', 'CWRType'), 'hidden')
 
+_pvs.tag_subject_of(('CWAttribute', 'constrained_by', '*'), 'hidden')
+_pvs.tag_subject_of(('CWRelation', 'constrained_by', '*'), 'hidden')
+
+
 class SecurityViewMixIn(object):
     """mixin providing methods to display security information for a entity,
     relation or relation definition schema
@@ -61,18 +77,16 @@
             w(u'<tr><td>%s</td><td>' % _(action))
             if permissions is None:
                 groups = erschema.get_groups(action)
+                rqlexprs = sorted(e.expression for e in erschema.get_rqlexprs(action))
             else:
                 groups = permissions[action][0]
+                rqlexprs = permissions[action][1]
             # XXX get group entity and call it's incontext view
             groups = [u'<a class="%s" href="%s">%s</a>' % (
                 group, self._cw.build_url('cwgroup/%s' % group), label)
                       for group, label in sorted((_(g), g) for g in groups)]
             w(u'<br/>'.join(groups))
             w(u'</td><td>')
-            if permissions is None:
-                rqlexprs = sorted(e.expression for e in erschema.get_rqlexprs(action))
-            else:
-                rqlexprs = permissions[action][1]
             w(u'<br/>'.join(rqlexprs))
             w(u'</td></tr>\n')
         w(u'</table>')
@@ -108,13 +122,14 @@
 # global schema view ###########################################################
 
 class SchemaView(tabs.TabsMixin, StartupView):
+    """display schema information (graphically, listing tables...) in tabs"""
     __regid__ = 'schema'
     title = _('instance schema')
-    tabs = [_('schema-description'), _('schema-image'), _('schema-security')]
-    default_tab = 'schema-description'
+    tabs = [_('schema-image'), _('schema-entity-types'),
+            _('schema-relation-types'), _('schema-security')]
+    default_tab = 'schema-image'
 
     def call(self):
-        """display schema information"""
         self.w(u'<h1>%s</h1>' % _('Schema of the data model'))
         self.render_tabs(self.tabs, self.default_tab)
 
@@ -127,24 +142,28 @@
                  u'meta-data, but you can also display a <a href="%s">complete '
                  u'schema with meta-data</a>.</div>')
                % xml_escape(self._cw.build_url('view', vid='schemagraph', skipmeta=0)))
+        self.w(u'<div><a href="%s">%s</a></div>' %
+               (self._cw.build_url('view', vid='owl'),
+                self._cw._(u'Download schema as OWL')))
         self.w(u'<img src="%s" alt="%s"/>\n' % (
             xml_escape(self._cw.build_url('view', vid='schemagraph', skipmeta=1)),
             self._cw._("graphical representation of the instance'schema")))
 
 
-class SchemaDescriptionTab(StartupView):
-    __regid__ = 'schema-description'
+class SchemaETypeTab(StartupView):
+    __regid__ = 'schema-entity-types'
 
     def call(self):
-        rset = self._cw.execute('Any X ORDERBY N WHERE X is CWEType, X name N, '
-                                'X final FALSE')
-        self.wview('table', rset, displayfilter=True)
-        rset = self._cw.execute('Any X ORDERBY N WHERE X is CWRType, X name N, '
-                                'X final FALSE')
-        self.wview('table', rset, displayfilter=True)
-        owl_downloadurl = self._cw.build_url('view', vid='owl')
-        self.w(u'<div><a href="%s">%s</a></div>' %
-               (owl_downloadurl, self._cw._(u'Download schema as OWL')))
+        self.wview('table', self._cw.execute(
+            'Any X ORDERBY N WHERE X is CWEType, X name N, X final FALSE'))
+
+
+class SchemaRTypeTab(StartupView):
+    __regid__ = 'schema-relation-types'
+
+    def call(self):
+        self.wview('table', self._cw.execute(
+            'Any X ORDERBY N WHERE X is CWRType, X name N, X final FALSE'))
 
 
 class SchemaPermissionsTab(SecurityViewMixIn, StartupView):
@@ -152,7 +171,6 @@
     __select__ = StartupView.__select__ & match_user_groups('managers')
 
     def call(self, display_relations=True):
-        self._cw.add_css('cubicweb.acl.css')
         skiptypes = skip_types(self._cw)
         schema = self._cw.vreg.schema
         # compute entities
@@ -267,65 +285,67 @@
     __regid__ = 'cwetype-description'
     __select__ = tabs.PrimaryTab.__select__ & implements('CWEType')
 
-    def render_entity_attributes(self, entity, siderelations=None):
+    def render_entity_attributes(self, entity):
+        super(CWETypeDescriptionTab, self).render_entity_attributes(entity)
         _ = self._cw._
-        self.w(u'<div>%s</div>' % xml_escape(entity.description or u''))
+        # inheritance
+        if entity.specializes:
+            self.w(u'<div>%s' % _('Parent classes:'))
+            self.wview('csv', entity.related('specializes', 'subject'))
+            self.w(u'</div>')
+        if entity.reverse_specializes:
+            self.w(u'<div>%s' % _('Sub-classes:'))
+            self.wview('csv', entity.related('specializes', 'object'))
+            self.w(u'</div>')
         # entity schema image
-        url = entity.absolute_url(vid='schemagraph')
         self.w(u'<img src="%s" alt="%s"/>' % (
-            xml_escape(url),
+            xml_escape(entity.absolute_url(vid='schemagraph')),
             xml_escape(_('graphical schema for %s') % entity.name)))
         # entity schema attributes
-        self.w(u'<h2>%s</h2>' % _('Attributes'))
+        self.w(u'<h2>%s</h2>' % _('CWAttribute_plural'))
         rset = self._cw.execute(
-            'Any A,F,D,C,I,J,A,DE ORDERBY AA WHERE A is CWAttribute, '
+            'Any A,ON,D,C,A,DE,A, IDX,FTI,I18N,R,O,RN,S ORDERBY AA '
+            'WHERE A is CWAttribute, A from_entity S, S eid %(x)s, '
             'A ordernum AA, A defaultval D, A description DE, A cardinality C, '
-            'A fulltextindexed I, A internationalizable J, '
-            'A relation_type R, R name N, A to_entity O, O name F, '
-            'A from_entity S, S eid %(x)s',
+            'A fulltextindexed FTI, A internationalizable I18N, A indexed IDX, '
+            'A relation_type R, R name RN, A to_entity O, O name ON',
             {'x': entity.eid})
         self.wview('table', rset, 'null',
                    cellvids={0: 'rdef-name-cell',
                              3: 'etype-attr-cardinality-cell',
-                             6: 'rdef-constraints-cell'},
+                             4: 'rdef-constraints-cell',
+                             6: 'rdef-options-cell'},
                    headers=(_(u'name'), _(u'type'),
                             _(u'default value'), _(u'required'),
-                            _(u'fulltext indexed'), _(u'internationalizable'),
-                            _(u'constraints'), _(u'description')),
-                   mainindex=0)
+                            _(u'constraints'), _(u'description'), _('options')))
         # entity schema relations
-        self.w(u'<h2>%s</h2>' % _('Relations'))
+        self.w(u'<h2>%s</h2>' % _('CWRelation_plural'))
+        cellvids = {0: 'rdef-name-cell',
+                    2: 'etype-rel-cardinality-cell',
+                    3: 'rdef-constraints-cell',
+                    4: 'rdef-options-cell'}
+        headers= [_(u'name'), _(u'object type'), _(u'cardinality'),
+                  _(u'constraints'), _(u'options')]
         rset = self._cw.execute(
-            'Any A,TT,"i18ncard_"+SUBSTRING(C, 1, 1),K,A,TTN ORDERBY RN '
-            'WHERE A is CWRelation, A composite K, A cardinality C, '
-            'A relation_type R, R name RN, '
-            'A to_entity TT, TT name TTN, A from_entity S, S eid %(x)s',
+            'Any A,TT,"i18ncard_"+SUBSTRING(C,1,1),A,A, K,TTN,R,RN ORDERBY RN '
+            'WHERE A is CWRelation, A from_entity S, S eid %(x)s, '
+            'A composite K, A cardinality C, '
+            'A relation_type R, R name RN, A to_entity TT, TT name TTN',
             {'x': entity.eid})
         if rset:
             self.w(u'<h5>%s %s</h5>' % (entity.name, _('is subject of:')))
-        self.wview('table', rset, 'null',
-                   cellvids={0: 'rdef-name-cell',
-                             2: 'etype-rel-cardinality-cell',
-                             4: 'rdef-constraints-cell'},
-                   headers=(_(u'name'), _(u'object type'), _(u'cardinality'),
-                            _(u'composite'), _(u'constraints')),
-                   displaycols=range(5))
-        self.w(u'<br/>')
+            self.wview('table', rset, cellvids=cellvids, headers=headers)
         rset = self._cw.execute(
-            'Any A,TT,"i18ncard_"+SUBSTRING(C, 2, 1),K,A,TTN ORDERBY RN '
-            'WHERE A is CWRelation, A composite K, A cardinality C, '
-            'A relation_type R, R name RN, '
-            'A from_entity TT, TT name TTN, A to_entity O, O eid %(x)s',
+            'Any A,TT,"i18ncard_"+SUBSTRING(C,1,1),A,A, K,TTN,R,RN ORDERBY RN '
+            'WHERE A is CWRelation, A to_entity O, O eid %(x)s, '
+            'A composite K, A cardinality C, '
+            'A relation_type R, R name RN, A from_entity TT, TT name TTN',
             {'x': entity.eid})
         if rset:
+            cellvids[0] = 'rdef-object-name-cell'
+            headers[1] = _(u'subject type')
             self.w(u'<h5>%s %s</h5>' % (entity.name, _('is object of:')))
-        self.wview('table', rset, 'null',
-                   cellvids={0: 'rdef-object-name-cell',
-                             2: 'etype-rel-cardinality-cell',
-                             4: 'rdef-constraints-cell'},
-                   headers=(_(u'name'), _(u'subject type'), _(u'cardinality'),
-                            _(u'composite'), _(u'constraints')),
-                   displaycols=range(5))
+            self.wview('table', rset, cellvids=cellvids, headers=headers)
 
 
 class CWETypeAttributeCardinalityCell(baseviews.FinalView):
@@ -350,7 +370,7 @@
     __select__ = implements('CWEType')
 
     def cell_call(self, row, col):
-        viewer = SchemaViewer(self._cw)
+        viewer = schemaviewer.SchemaViewer(self._cw)
         entity = self.cw_rset.get_entity(row, col)
         eschema = self._cw.vreg.schema.eschema(entity.name)
         layout = viewer.visit_entityschema(eschema)
@@ -363,12 +383,12 @@
     __select__ = implements('CWEType') & authenticated_user()
 
     def cell_call(self, row, col):
-        self._cw.add_css('cubicweb.acl.css')
         entity = self.cw_rset.get_entity(row, col)
         eschema = self._cw.vreg.schema.eschema(entity.name)
-        self.w(u'<div style="margin: 0px 1.5em">')
+        self.w(u'<h4>%s</h4>' % _('This entity type permissions:').capitalize())
         self.permissions_table(eschema)
-        self.w(u'<h4>%s</h4>' % _('attributes permissions:').capitalize())
+        self.w(u'<div style="margin: 0px 1.5em">')
+        self.w(u'<h4>%s</h4>' % _('Attributes permissions:').capitalize())
         for attr, etype in  eschema.attribute_definitions():
             if attr not in META_RTYPES:
                 rdef = eschema.rdef(attr)
@@ -409,16 +429,20 @@
 
 
 class CWETypeViewsTab(EntityView):
+    """possible views for this entity type"""
     __regid__ = 'cwetype-views'
     __select__ = EntityView.__select__ & implements('CWEType')
 
     def cell_call(self, row, col):
         entity = self.cw_rset.get_entity(row, col)
-        etype = entity.name
         _ = self._cw._
-        # possible views for this entity type
-        views = [(_(view.title),) for view in self.possible_views(etype)]
-        self.wview('pyvaltable', pyvalue=sorted(views), headers=(_(u'views'),))
+        self.w('<div>%s</div>' % _('Non exhaustive list of views that may '
+                                   'apply to entities of this type'))
+        views = [(view.content_type, view.__regid__, _(view.title))
+                 for view in self.possible_views(entity.name)]
+        self.wview('pyvaltable', pyvalue=sorted(views),
+                   headers=(_(u'content type'), _(u'view identifier'),
+                            _(u'view title')))
 
     def possible_views(self, etype):
         rset = self._cw.etype_rset(etype)
@@ -450,22 +474,21 @@
     __regid__ = 'cwrtype-description'
     __select__ = implements('CWRType')
 
-    def render_entity_attributes(self, entity, siderelations=None):
+    def render_entity_attributes(self, entity):
+        super(CWRTypeDescriptionTab, self).render_entity_attributes(entity)
         _ = self._cw._
-        self.w(u'<div>%s</div>' % xml_escape(entity.description or u''))
-        rschema = self._cw.vreg.schema.rschema(entity.name)
-        if not rschema.final:
+        if not entity.final:
             msg = _('graphical schema for %s') % entity.name
             self.w(tags.img(src=entity.absolute_url(vid='schemagraph'),
                             alt=msg))
-        rset = self._cw.execute('Any R,C,CC,R WHERE R is CWRelation, '
+        rset = self._cw.execute('Any R,C,R,R, RT WHERE '
                                 'R relation_type RT, RT eid %(x)s, '
-                                'R cardinality C, R composite CC',
-                                {'x': entity.eid})
+                                'R cardinality C', {'x': entity.eid})
         self.wview('table', rset, 'null',
-                   headers=(_(u'relation'),  _(u'cardinality'), _(u'composite'),
-                            _(u'constraints')),
-                   cellvids={3: 'rdef-constraints-cell'})
+                   headers=(_(u'relation'),  _(u'cardinality'), _(u'constraints'),
+                            _(u'options')),
+                   cellvids={2: 'rdef-constraints-cell',
+                             3: 'rdef-options-cell'})
 
 
 class CWRTypePermTab(SecurityViewMixIn, EntityView):
@@ -473,7 +496,6 @@
     __select__ = implements('CWRType') & authenticated_user()
 
     def cell_call(self, row, col):
-        self._cw.add_css('cubicweb.acl.css')
         entity = self.cw_rset.get_entity(row, col)
         rschema = self._cw.vreg.schema.rschema(entity.name)
         self.grouped_permissions_table(rschema)
@@ -481,27 +503,33 @@
 
 # CWAttribute / CWRelation #####################################################
 
-class CWRDEFPrimaryView(tabs.TabbedPrimaryView):
+class RDEFPrimaryView(tabs.TabbedPrimaryView):
     __select__ = implements('CWRelation', 'CWAttribute')
-    tabs = [_('cwrdef-description'), _('cwrdef-permissions')]
-    default_tab = 'cwrdef-description'
+    tabs = [_('rdef-description'), _('rdef-permissions')]
+    default_tab = 'rdef-description'
 
-class CWRDEFDescriptionTab(tabs.PrimaryTab):
-    __regid__ = 'cwrdef-description'
+
+class RDEFDescriptionTab(tabs.PrimaryTab):
+    __regid__ = 'rdef-description'
     __select__ = implements('CWRelation', 'CWAttribute')
 
-class CWRDEFPermTab(SecurityViewMixIn, EntityView):
-    __regid__ = 'cwrdef-permissions'
+    def render_entity_attributes(self, entity):
+        super(RDEFDescriptionTab, self).render_entity_attributes(entity)
+        rdef = entity.yams_schema()
+        if rdef.constraints:
+            self.w(u'<h4>%s</h4>' % self._cw._('constrained_by'))
+            self.w(entity.view('rdef-constraints-cell'))
+
+
+class RDEFPermTab(SecurityViewMixIn, EntityView):
+    __regid__ = 'rdef-permissions'
     __select__ = implements('CWRelation', 'CWAttribute') & authenticated_user()
 
     def cell_call(self, row, col):
-        entity = self.cw_rset.get_entity(row, col)
-        rschema = self._cw.vreg.schema.rschema(entity.rtype.name)
-        rdef = rschema.rdefs[(entity.stype.name, entity.otype.name)]
-        self.permissions_table(rdef)
+        self.permissions_table(self.cw_rset.get_entity(row, col).yams_schema())
 
 
-class CWRDEFNameView(tableview.CellView):
+class RDEFNameView(tableview.CellView):
     """display relation name and its translation only in a cell view, link to
     relation definition's primary view (for use in entity type relations table
     for instance)
@@ -512,12 +540,12 @@
     def cell_call(self, row, col):
         entity = self.cw_rset.get_entity(row, col)
         rtype = entity.relation_type[0].name
-        # XXX use contect entity + pgettext
+        # XXX use context entity + pgettext
         self.w(u'<a href="%s">%s</a> (%s)' % (
             entity.absolute_url(), rtype, self._cw._(rtype)))
 
-class CWRDEFObjectNameView(tableview.CellView):
-    """same as CWRDEFNameView but when the context is the object entity
+class RDEFObjectNameView(tableview.CellView):
+    """same as RDEFNameView but when the context is the object entity
     """
     __regid__ = 'rdef-object-name-cell'
     __select__ = implements('CWRelation', 'CWAttribute')
@@ -525,11 +553,11 @@
     def cell_call(self, row, col):
         entity = self.cw_rset.get_entity(row, col)
         rtype = entity.relation_type[0].name
-        # XXX use contect entity + pgettext
+        # XXX use context entity + pgettext
         self.w(u'<a href="%s">%s</a> (%s)' % (
             entity.absolute_url(), rtype, self._cw.__(rtype + '_object')))
 
-class CWRDEFConstraintsCell(EntityView):
+class RDEFConstraintsCell(EntityView):
     __regid__ = 'rdef-constraints-cell'
     __select__ = implements('CWAttribute', 'CWRelation')
 
@@ -540,6 +568,41 @@
         constraints = [xml_escape(str(c)) for c in getattr(rdef, 'constraints')]
         self.w(u'<br/>'.join(constraints))
 
+class CWAttributeOptionsCell(EntityView):
+    __regid__ = 'rdef-options-cell'
+    __select__ = implements('CWAttribute')
+
+    def cell_call(self, row, col):
+        entity = self.cw_rset.get_entity(row, col)
+        options = []
+        if entity.indexed:
+            options.append(self._cw._('indexed'))
+        if entity.fulltextindexed:
+            options.append(self._cw._('fulltextindexed'))
+        if entity.internationalizable:
+            options.append(self._cw._('internationalizable'))
+        self.w(u','.join(options))
+
+class CWRelationOptionsCell(EntityView):
+    __regid__ = 'rdef-options-cell'
+    __select__ = implements('CWRelation',)
+
+    def cell_call(self, row, col):
+        entity = self.cw_rset.get_entity(row, col)
+        rtype = entity.rtype
+        options = []
+        if rtype.symmetric:
+            options.append(self._cw._('symmetric'))
+        if rtype.inlined:
+            options.append(self._cw._('inlined'))
+        if rtype.fulltext_container:
+            options.append('%s=%s' % (self._cw._('fulltext_container'),
+                                      self._cw._(rtype.fulltext_container)))
+        if entity.composite:
+            options.append('%s=%s' % (self._cw._('composite'),
+                                      self._cw._(entity.composite)))
+        self.w(u','.join(options))
+
 
 # schema images ###############################################################
 
--- a/web/views/tableview.py	Tue Apr 13 19:43:51 2010 +0200
+++ b/web/views/tableview.py	Wed Apr 14 08:49:23 2010 +0200
@@ -87,10 +87,12 @@
                 continue
         return None
 
-    def displaycols(self, displaycols):
+    def displaycols(self, displaycols, headers):
         if displaycols is None:
             if 'displaycols' in self._cw.form:
                 displaycols = [int(idx) for idx in self._cw.form['displaycols']]
+            elif headers is not None:
+                displaycols = range(len(headers))
             else:
                 displaycols = range(len(self.cw_rset.syntax_tree().children[0].selection))
         return displaycols
@@ -127,7 +129,7 @@
                     hidden = False
             if displayactions is None and 'displayactions' in req.form:
                 displayactions = True
-        displaycols = self.displaycols(displaycols)
+        displaycols = self.displaycols(displaycols, headers)
         fromformfilter = 'fromformfilter' in req.form
         # if fromformfilter is true, this is an ajax call and we only want to
         # replace the inner div, so don't regenerate everything under the if
@@ -297,7 +299,7 @@
         """Dumps a table displaying a composite query"""
         actrql = self._cw.form['actualrql']
         self._cw.ensure_ro_rql(actrql)
-        displaycols = self.displaycols(displaycols)
+        displaycols = self.displaycols(displaycols, headers)
         if displayactions is None and 'displayactions' in self._cw.form:
             displayactions = True
         if divid is None and 'divid' in self._cw.form:
--- a/web/views/workflow.py	Tue Apr 13 19:43:51 2010 +0200
+++ b/web/views/workflow.py	Wed Apr 14 08:49:23 2010 +0200
@@ -33,6 +33,11 @@
 _pvs.tag_subject_of(('Workflow', 'initial_state', '*'), 'hidden')
 _pvs.tag_object_of(('*', 'state_of', 'Workflow'), 'hidden')
 _pvs.tag_object_of(('*', 'transition_of', 'Workflow'), 'hidden')
+_pvs.tag_object_of(('*', 'wf_info_for', '*'), 'hidden')
+for rtype in ('in_state', 'by_transition', 'from_state', 'to_state'):
+    _pvs.tag_subject_of(('*', rtype, '*'), 'hidden')
+    _pvs.tag_object_of(('*', rtype, '*'), 'hidden')
+_pvs.tag_object_of(('*', 'wf_info_for', '*'), 'hidden')
 
 _abaa = uicfg.actionbox_appearsin_addmenu
 _abaa.tag_subject_of(('BaseTransition', 'condition', 'RQLExpression'), False)