[uicfg] uicfg.py moves from web/ to web/views/ (prepares #2406609)
authorAurelien Campeas <aurelien.campeas@logilab.fr>
Thu, 10 Jan 2013 18:34:10 +0100
changeset 8665 e65af61bde7d
parent 8664 29652410c317
child 8666 1dd655788ece
[uicfg] uicfg.py moves from web/ to web/views/ (prepares #2406609) We are about to make uicfg selectable. Registrable / selectable views and helpers live in web/views. Hence the move. Backward compat is put in place. However CubicWeb imports of uicfg are updated to the new location.
devtools/devctl.py
doc/book/en/devweb/views/boxes.rst
doc/book/en/devweb/views/primary.rst
doc/book/en/devweb/views/reledit.rst
doc/book/en/tutorials/advanced/part05_ui-advanced.rst
web/formfields.py
web/test/unittest_formwidgets.py
web/test/unittest_reledit.py
web/test/unittest_uicfg.py
web/test/unittest_views_editforms.py
web/uicfg.py
web/uihelper.py
web/views/actions.py
web/views/autoform.py
web/views/basecomponents.py
web/views/bookmark.py
web/views/cwproperties.py
web/views/cwsources.py
web/views/cwuser.py
web/views/editforms.py
web/views/emailaddress.py
web/views/forms.py
web/views/primary.py
web/views/reledit.py
web/views/schema.py
web/views/startup.py
web/views/uicfg.py
web/views/workflow.py
--- a/devtools/devctl.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/devtools/devctl.py	Thu Jan 10 18:34:10 2013 +0100
@@ -97,7 +97,7 @@
                 break
     # fresh rtags
     from cubicweb import rtags
-    from cubicweb.web import uicfg
+    from cubicweb.web.views import uicfg
     rtags.RTAGS[:] = []
     reload(uicfg)
 
@@ -129,7 +129,7 @@
 def _generate_schema_pot(w, vreg, schema, libconfig=None):
     from copy import deepcopy
     from cubicweb.i18n import add_msg
-    from cubicweb.web import uicfg
+    from cubicweb.web.views import uicfg
     from cubicweb.schema import NO_I18NCONTEXT, CONSTRAINTS
     w('# schema pot file, generated on %s\n'
       % datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
--- a/doc/book/en/devweb/views/boxes.rst	Thu Jan 10 13:03:38 2013 +0100
+++ b/doc/book/en/devweb/views/boxes.rst	Thu Jan 10 18:34:10 2013 +0100
@@ -15,7 +15,7 @@
 which the box is displayed). By default, the links generated in this
 box are computed from the schema properties of the displayed entity,
 but it is possible to explicitly specify them thanks to the
-`cubicweb.web.uicfg.rmode` *relation tag*:
+`cubicweb.web.views.uicfg.rmode` *relation tag*:
 
 * `link`, indicates that a relation is in general created pointing
   to an existing entity and that we should not to display a link
--- a/doc/book/en/devweb/views/primary.rst	Thu Jan 10 13:03:38 2013 +0100
+++ b/doc/book/en/devweb/views/primary.rst	Thu Jan 10 18:34:10 2013 +0100
@@ -51,7 +51,7 @@
 
 .. sourcecode:: python
 
-   from cubicweb.web import uicfg
+   from cubicweb.web.views import uicfg
    uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
 
 **Relations** can be either displayed in one of the three sections or hidden.
--- a/doc/book/en/devweb/views/reledit.rst	Thu Jan 10 13:03:38 2013 +0100
+++ b/doc/book/en/devweb/views/reledit.rst	Thu Jan 10 18:34:10 2013 +0100
@@ -68,7 +68,7 @@
 
 The behaviour of reledited attributes/relations can be finely
 controlled using the reledit_ctrl rtag, defined in
-:mod:`cubicweb.web.uicfg`.
+:mod:`cubicweb.web.views.uicfg`.
 
 This rtag provides four control variables:
 
@@ -93,7 +93,7 @@
 .. sourcecode:: python
 
     from logilab.mtconverter import xml_escape
-    from cubicweb.web.uicfg import reledit_ctrl
+    from cubicweb.web.views.uicfg import reledit_ctrl
     reledit_ctrl.tag_attribute(('Company', 'name'),
                                {'reload': lambda x:x.eid,
                                 'default_value': xml_escape(u'<logilab tastes better>')})
@@ -125,7 +125,7 @@
 
 .. sourcecode:: python
 
-    import uicfg.primaryview_display_ctrl as _pvdc
+    from cubicweb.web.views.uicfg import primaryview_display_ctrl as _pvdc
     _pvdc.tag_attribute(('Company', 'name'), {'vid': 'incontext'})
 
 To deactivate it everywhere it's used automatically, you may use the code snippet
--- a/doc/book/en/tutorials/advanced/part05_ui-advanced.rst	Thu Jan 10 13:03:38 2013 +0100
+++ b/doc/book/en/tutorials/advanced/part05_ui-advanced.rst	Thu Jan 10 18:34:10 2013 +0100
@@ -215,7 +215,7 @@
 
     from logilab.common.decorators import monkeypatch
     from cubicweb import ValidationError
-    from cubicweb.web import uicfg, component
+    from cubicweb.web.views import uicfg, component
     from cubicweb.web.views import basecontrollers
 
     # hide displayed_on relation using uicfg since it will be displayed by the box below
--- a/web/formfields.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/formfields.py	Thu Jan 10 18:34:10 2013 +0100
@@ -79,7 +79,8 @@
 from cubicweb import Binary, tags, uilib
 from cubicweb.utils import support_args
 from cubicweb.web import INTERNAL_FIELD_VALUE, ProcessFormError, eid_param, \
-     formwidgets as fw, uicfg
+     formwidgets as fw
+from cubicweb.web.views import uicfg
 
 
 class UnmodifiedField(Exception):
--- a/web/test/unittest_formwidgets.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/test/unittest_formwidgets.py	Thu Jan 10 18:34:10 2013 +0100
@@ -20,7 +20,7 @@
 from logilab.common.testlib import TestCase, unittest_main, mock_object as mock
 
 from cubicweb.devtools import TestServerConfiguration, fake
-from cubicweb.web import uicfg, formwidgets, formfields
+from cubicweb.web import formwidgets, formfields
 
 from cubes.file.entities import File
 
--- a/web/test/unittest_reledit.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/test/unittest_reledit.py	Thu Jan 10 18:34:10 2013 +0100
@@ -20,7 +20,7 @@
 """
 
 from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.web.uicfg import reledit_ctrl
+from cubicweb.web.views.uicfg import reledit_ctrl
 
 class ReleditMixinTC(object):
 
--- a/web/test/unittest_uicfg.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/test/unittest_uicfg.py	Thu Jan 10 18:34:10 2013 +0100
@@ -18,7 +18,8 @@
 import copy
 from logilab.common.testlib import tag
 from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.web import uicfg, uihelper, formwidgets as fwdgs
+from cubicweb.web import uihelper, formwidgets as fwdgs
+from cubicweb.web.views import uicfg
 
 abaa = uicfg.actionbox_appearsin_addmenu
 
--- a/web/test/unittest_views_editforms.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/test/unittest_views_editforms.py	Thu Jan 10 18:34:10 2013 +0100
@@ -22,7 +22,7 @@
 from logilab.common.compat import any
 
 from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.web import uicfg
+from cubicweb.web.views import uicfg
 from cubicweb.web.formwidgets import AutoCompletionWidget
 
 AFFK = uicfg.autoform_field_kwargs
--- a/web/uicfg.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/uicfg.py	Thu Jan 10 18:34:10 2013 +0100
@@ -15,422 +15,15 @@
 #
 # You should have received a copy of the GNU Lesser General Public License along
 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
-"""This module (``cubicweb.web.uicfg``) regroups a set of structures that may be
-used to configure various options of the generated web interface.
-
-To configure the interface generation, we use ``RelationTag`` objects.
-
-Index view configuration
-````````````````````````
-:indexview_etype_section:
-   entity type category in the index/manage page. May be one of:
-
-      * ``application``
-      * ``system``
-      * ``schema``
-      * ``subobject`` (not displayed by default)
-
-   By default only entities on the ``application`` category are shown.
-
-.. sourcecode:: python
-
-    from cubicweb.web import uicfg
-    # force hiding
-    uicfg.indexview_etype_section['HideMe'] = 'subobject'
-    # force display
-    uicfg.indexview_etype_section['ShowMe'] = 'application'
-
-
-Actions box configuration
-`````````````````````````
-:actionbox_appearsin_addmenu:
-  simple boolean relation tags used to control the "add entity" submenu.
-  Relations whose rtag is True will appears, other won't.
-
-.. sourcecode:: python
-
-   # Adds all subjects of the entry_of relation in the add menu of the ``Blog``
-   # primary view
-   uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True)
+"""
+This module is now deprecated, see web.views.uicfg.
 """
 __docformat__ = "restructuredtext en"
 
 from warnings import warn
-
-from logilab.common.compat import any
-
-from cubicweb import neg_role
-from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet,
-                            RelationTagsDict, NoTargetRelationTagsDict,
-                            register_rtag, _ensure_str_key)
-from cubicweb.schema import META_RTYPES, INTERNAL_TYPES, WORKFLOW_TYPES
-
-
-# primary view configuration ##################################################
-
-def init_primaryview_section(rtag, sschema, rschema, oschema, role):
-    if rtag.get(sschema, rschema, oschema, role) is None:
-        rdef = rschema.rdef(sschema, oschema)
-        if rschema.final:
-            if rschema.meta or sschema.is_metadata(rschema) \
-                    or oschema.type in ('Password', 'Bytes'):
-                section = 'hidden'
-            else:
-                section = 'attributes'
-        else:
-            if rdef.role_cardinality(role) in '1+':
-                section = 'attributes'
-            elif rdef.composite == neg_role(role):
-                section = 'relations'
-            else:
-                section = 'sideboxes'
-        rtag.tag_relation((sschema, rschema, oschema, role), section)
-
-primaryview_section = RelationTags('primaryview_section',
-                                   init_primaryview_section,
-                                   frozenset(('attributes', 'relations',
-                                              'sideboxes', 'hidden')))
-
-
-class DisplayCtrlRelationTags(NoTargetRelationTagsDict):
-    def __init__(self, *args, **kwargs):
-        super(DisplayCtrlRelationTags, self).__init__(*args, **kwargs)
-        self.counter = 0
-
-def init_primaryview_display_ctrl(rtag, sschema, rschema, oschema, role):
-    if role == 'subject':
-        oschema = '*'
-    else:
-        sschema = '*'
-    rtag.counter += 1
-    rtag.setdefault((sschema, rschema, oschema, role), 'order', rtag.counter)
-
-primaryview_display_ctrl = DisplayCtrlRelationTags('primaryview_display_ctrl',
-                                                   init_primaryview_display_ctrl)
+from cubicweb.web.views.uicfg import *
 
 
-# index view configuration ####################################################
-# entity type section in the index/manage page. May be one of
-# * 'application'
-# * 'system'
-# * 'schema'
-# * 'hidden'
-# * 'subobject' (not displayed by default)
-
-class InitializableDict(dict):
-    def __init__(self, *args, **kwargs):
-        super(InitializableDict, self).__init__(*args, **kwargs)
-        register_rtag(self)
-        self.__defaults = dict(self)
-
-    def init(self, schema, check=True):
-        self.update(self.__defaults)
-        for eschema in schema.entities():
-            if eschema.final:
-                continue
-            if eschema.schema_entity():
-                self.setdefault(eschema, 'schema')
-            elif eschema in INTERNAL_TYPES or eschema in WORKFLOW_TYPES:
-                self.setdefault(eschema, 'system')
-            elif eschema.is_subobject(strict=True):
-                self.setdefault(eschema, 'subobject')
-            else:
-                self.setdefault(eschema, 'application')
-
-indexview_etype_section = InitializableDict(
-    EmailAddress='subobject',
-    Bookmark='system',
-    # entity types in the 'system' table by default (managers only)
-    CWUser='system', CWGroup='system',
-    )
-
-# autoform.AutomaticEntityForm configuration ##################################
-
-def _formsections_as_dict(formsections):
-    result = {}
-    for formsection in formsections:
-        formtype, section = formsection.split('_', 1)
-        result[formtype] = section
-    return result
-
-def _card_and_comp(sschema, rschema, oschema, role):
-    rdef = rschema.rdef(sschema, oschema)
-    if role == 'subject':
-        card = rdef.cardinality[0]
-        composed = not rschema.final and rdef.composite == 'object'
-    else:
-        card = rdef.cardinality[1]
-        composed = not rschema.final and rdef.composite == 'subject'
-    return card, composed
-
-class AutoformSectionRelationTags(RelationTagsSet):
-    """autoform relations'section"""
-
-    _allowed_form_types = ('main', 'inlined', 'muledit')
-    _allowed_values = {'main': ('attributes', 'inlined', 'relations',
-                                'metadata', 'hidden'),
-                       'inlined': ('attributes', 'inlined', 'hidden'),
-                       'muledit': ('attributes', 'hidden'),
-                       }
-
-    def init(self, schema, check=True):
-        super(AutoformSectionRelationTags, self).init(schema, check)
-        self.apply(schema, self._initfunc_step2)
-
-    @staticmethod
-    def _initfunc(self, sschema, rschema, oschema, role):
-        formsections = self.init_get(sschema, rschema, oschema, role)
-        if formsections is None:
-            formsections = self.tag_container_cls()
-        if not any(tag.startswith('inlined') for tag in formsections):
-            if not rschema.final:
-                negsects = self.init_get(sschema, rschema, oschema, neg_role(role))
-                if 'main_inlined' in negsects:
-                    formsections.add('inlined_hidden')
-        key = _ensure_str_key( (sschema, rschema, oschema, role) )
-        self._tagdefs[key] = formsections
-
-    @staticmethod
-    def _initfunc_step2(self, sschema, rschema, oschema, role):
-        formsections = self.get(sschema, rschema, oschema, role)
-        sectdict = _formsections_as_dict(formsections)
-        if rschema in META_RTYPES:
-            sectdict.setdefault('main', 'hidden')
-            sectdict.setdefault('muledit', 'hidden')
-            sectdict.setdefault('inlined', 'hidden')
-        elif role == 'subject' and rschema in sschema.meta_attributes():
-            # meta attribute, usually embeded by the described attribute's field
-            # (eg RichTextField, FileField...)
-            sectdict.setdefault('main', 'hidden')
-            sectdict.setdefault('muledit', 'hidden')
-            sectdict.setdefault('inlined', 'hidden')
-        # ensure we have a tag for each form type
-        if not 'main' in sectdict:
-            if not rschema.final and (
-                sectdict.get('inlined') == 'attributes' or
-                'inlined_attributes' in self.init_get(sschema, rschema, oschema,
-                                                      neg_role(role))):
-                sectdict['main'] = 'hidden'
-            elif sschema.is_metadata(rschema):
-                sectdict['main'] = 'metadata'
-            else:
-                card, composed = _card_and_comp(sschema, rschema, oschema, role)
-                if card in '1+':
-                    sectdict['main'] = 'attributes'
-                    if not 'muledit' in sectdict:
-                        sectdict['muledit'] = 'attributes'
-                elif rschema.final:
-                    sectdict['main'] = 'attributes'
-                else:
-                    sectdict['main'] = 'relations'
-        if not 'muledit' in sectdict:
-            sectdict['muledit'] = 'hidden'
-            if sectdict['main'] == 'attributes':
-                card, composed = _card_and_comp(sschema, rschema, oschema, role)
-                if card in '1+' and not composed:
-                    sectdict['muledit'] = 'attributes'
-        if not 'inlined' in sectdict:
-            sectdict['inlined'] = sectdict['main']
-        # recompute formsections and set it to avoid recomputing
-        for formtype, section in sectdict.iteritems():
-            formsections.add('%s_%s' % (formtype, section))
-
-    def tag_relation(self, key, formtype, section):
-        if isinstance(formtype, tuple):
-            for ftype in formtype:
-                self.tag_relation(key, ftype, section)
-            return
-        assert formtype in self._allowed_form_types, \
-               'formtype should be in (%s), not %s' % (
-            ','.join(self._allowed_form_types), formtype)
-        assert section in self._allowed_values[formtype], \
-               'section for %s should be in (%s), not %s' % (
-            formtype, ','.join(self._allowed_values[formtype]), section)
-        rtags = self._tagdefs.setdefault(_ensure_str_key(key),
-                                         self.tag_container_cls())
-        # remove previous section for this form type if any
-        if rtags:
-            for tag in rtags.copy():
-                if tag.startswith(formtype):
-                    rtags.remove(tag)
-        rtags.add('%s_%s' % (formtype, section))
-        return rtags
-
-    def init_get(self, stype, rtype, otype, tagged):
-        key = (stype, rtype, otype, tagged)
-        rtags = {}
-        for key in self._get_keys(stype, rtype, otype, tagged):
-            tags = self._tagdefs.get(key, ())
-            for tag in tags:
-                assert '_' in tag, (tag, tags)
-                section, value = tag.split('_', 1)
-                rtags[section] = value
-        cls = self.tag_container_cls
-        rtags = cls('_'.join([section,value]) for section,value in rtags.iteritems())
-        return rtags
-
+warn('[3.16] moved to cubicweb.web.views.uicfg',
+     DeprecationWarning, stacklevel=2)
 
-    def get(self, *key):
-        # overriden to avoid recomputing done in parent classes
-        return self._tagdefs.get(key, ())
-
-    def relations_by_section(self, entity, formtype, section, permission,
-                             strict=False):
-        """return a list of (relation schema, target schemas, role) for the
-        given entity matching categories and permission.
-
-        `strict`:
-          bool telling if having local role is enough (strict = False) or not
-        """
-        tag = '%s_%s' % (formtype, section)
-        eschema  = entity.e_schema
-        permsoverrides = autoform_permissions_overrides
-        if entity.has_eid():
-            eid = entity.eid
-        else:
-            eid = None
-            strict = False
-        if permission == 'update':
-            assert section in ('attributes', 'metadata', 'hidden')
-            relpermission = 'add'
-        else:
-            assert section not in ('attributes', 'metadata', 'hidden')
-            relpermission = permission
-        cw = entity._cw
-        for rschema, targetschemas, role in eschema.relation_definitions(True):
-            _targetschemas = []
-            for tschema in targetschemas:
-                # check section's tag first, potentially lower cost than
-                # checking permission which may imply rql queries
-                if not tag in self.etype_get(eschema, rschema, role, tschema):
-                    continue
-                rdef = rschema.role_rdef(eschema, tschema, role)
-                if rschema.final:
-                    if not rdef.has_perm(cw, permission, eid=eid,
-                                         creating=eid is None):
-                        continue
-                elif strict or not rdef.has_local_role(relpermission):
-                    if role == 'subject':
-                        if not rdef.has_perm(cw, relpermission, fromeid=eid):
-                            continue
-                    elif role == 'object':
-                        if not rdef.has_perm(cw, relpermission, toeid=eid):
-                            continue
-                _targetschemas.append(tschema)
-            if not _targetschemas:
-                continue
-            targetschemas = _targetschemas
-            rdef = eschema.rdef(rschema, role=role, targettype=targetschemas[0])
-            # XXX tag allowing to hijack the permission machinery when
-            # permission is not verifiable until the entity is actually
-            # created...
-            if eid is None and '%s_on_new' % permission in permsoverrides.etype_get(eschema, rschema, role):
-                yield (rschema, targetschemas, role)
-                continue
-            if not rschema.final and role == 'subject':
-                # on relation with cardinality 1 or ?, we need delete perm as well
-                # if the relation is already set
-                if (relpermission == 'add'
-                    and rdef.role_cardinality(role) in '1?'
-                    and eid and entity.related(rschema.type, role)
-                    and not rdef.has_perm(cw, 'delete', fromeid=eid,
-                                          toeid=entity.related(rschema.type, role)[0][0])):
-                    continue
-            elif role == 'object':
-                # on relation with cardinality 1 or ?, we need delete perm as well
-                # if the relation is already set
-                if (relpermission == 'add'
-                    and rdef.role_cardinality(role) in '1?'
-                    and eid and entity.related(rschema.type, role)
-                    and not rdef.has_perm(cw, 'delete', toeid=eid,
-                                          fromeid=entity.related(rschema.type, role)[0][0])):
-                    continue
-            yield (rschema, targetschemas, role)
-
-autoform_section = AutoformSectionRelationTags('autoform_section')
-
-# relations'field class
-autoform_field = RelationTags('autoform_field')
-
-# relations'field explicit kwargs (given to field's __init__)
-autoform_field_kwargs = RelationTagsDict('autoform_field_kwargs')
-
-
-# set of tags of the form <action>_on_new on relations. <action> is a
-# schema action (add/update/delete/read), and when such a tag is found
-# permissions checking is by-passed and supposed to be ok
-autoform_permissions_overrides = RelationTagsSet('autoform_permissions_overrides')
-
-class ReleditTags(NoTargetRelationTagsDict):
-    """Associate to relation a dictionary to control `reledit` (e.g. edition of
-    attributes / relations from within views).
-
-    Possible keys and associated values are:
-
-    * `novalue_label`, alternative default value (shown when there is no value).
-
-    * `novalue_include_rtype`, when `novalue_label` is not specified, this boolean
-      flag control wether the generated default value should contains the
-      relation label or not. Will be the opposite of the `showlabel` value found
-      in the `primaryview_display_ctrl` rtag by default.
-
-    * `reload`, boolean, eid (to reload to) or function taking subject and
-      returning bool/eid. This is useful when editing a relation (or attribute)
-      that impacts the url or another parts of the current displayed
-      page. Defaults to False.
-
-    * `rvid`, alternative view id (as str) for relation or composite edition.
-      Default is 'autolimited'.
-
-    * `edit_target`, may be either 'rtype' (to edit the relation) or 'related'
-      (to edit the related entity).  This controls whether to edit the relation
-      or the target entity of the relation.  Currently only one-to-one relations
-      support target entity edition. By default, the 'related' option is taken
-      whenever the relation is composite.
-    """
-    _keys = frozenset('novalue_label novalue_include_rtype reload rvid edit_target'.split())
-
-    def tag_relation(self, key, tag):
-        for tagkey in tag.iterkeys():
-            assert tagkey in self._keys, 'tag %r not in accepted tags: %r' % (tag, self._keys)
-        return super(ReleditTags, self).tag_relation(key, tag)
-
-def init_reledit_ctrl(rtag, sschema, rschema, oschema, role):
-    values = rtag.get(sschema, rschema, oschema, role)
-    if not rschema.final:
-        composite = rschema.rdef(sschema, oschema).composite == role
-        if role == 'subject':
-            oschema = '*'
-        else:
-            sschema = '*'
-        edittarget = values.get('edit_target')
-        if edittarget not in (None, 'rtype', 'related'):
-            rtag.warning('reledit: wrong value for edit_target on relation %s: %s',
-                         rschema, edittarget)
-            edittarget = None
-        if not edittarget:
-            edittarget = 'related' if composite else 'rtype'
-            rtag.tag_relation((sschema, rschema, oschema, role),
-                              {'edit_target': edittarget})
-    if not 'novalue_include_rtype' in values:
-        showlabel = primaryview_display_ctrl.get(
-            sschema, rschema, oschema, role).get('showlabel', True)
-        rtag.tag_relation((sschema, rschema, oschema, role),
-                          {'novalue_include_rtype': not showlabel})
-
-reledit_ctrl = ReleditTags('reledit', init_reledit_ctrl)
-
-# boxes.EditBox configuration #################################################
-
-# 'link' / 'create' relation tags, used to control the "add entity" submenu
-def init_actionbox_appearsin_addmenu(rtag, sschema, rschema, oschema, role):
-    if rtag.get(sschema, rschema, oschema, role) is None:
-        if rschema in META_RTYPES:
-            rtag.tag_relation((sschema, rschema, oschema, role), False)
-            return
-        rdef = rschema.rdef(sschema, oschema)
-        if not rdef.role_cardinality(role) in '?1' and rdef.composite == role:
-            rtag.tag_relation((sschema, rschema, oschema, role), True)
-
-actionbox_appearsin_addmenu = RelationTagsBool('actionbox_appearsin_addmenu',
-                                               init_actionbox_appearsin_addmenu)
--- a/web/uihelper.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/uihelper.py	Thu Jan 10 18:34:10 2013 +0100
@@ -45,7 +45,7 @@
 """
 __docformat__ = "restructuredtext en"
 
-from cubicweb.web import uicfg
+from cubicweb.web.views import uicfg
 from functools import partial
 
 def _tag_rel(rtag, etype, attr, desttype='*', *args, **kwargs):
--- a/web/views/actions.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/actions.py	Thu Jan 10 18:34:10 2013 +0100
@@ -32,8 +32,8 @@
     authenticated_user, match_user_groups, match_search_state,
     has_permission, has_add_permission, is_instance, debug_mode,
     )
-from cubicweb.web import uicfg, controller, action
-from cubicweb.web.views import linksearch_select_url, vid_from_rset
+from cubicweb.web import controller, action
+from cubicweb.web.views import uicfg, linksearch_select_url, vid_from_rset
 
 
 class has_editable_relation(EntityPredicate):
--- a/web/views/autoform.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/autoform.py	Thu Jan 10 18:34:10 2013 +0100
@@ -135,9 +135,9 @@
     match_kwargs, match_form_params, non_final_entity,
     specified_etype_implements)
 from cubicweb.utils import json_dumps
-from cubicweb.web import (stdmsgs, uicfg, eid_param,
+from cubicweb.web import (stdmsgs, eid_param,
                           form as f, formwidgets as fw, formfields as ff)
-from cubicweb.web.views import forms
+from cubicweb.web.views import uicfg, forms
 from cubicweb.web.views.ajaxcontroller import ajaxfunc
 
 _AFS = uicfg.autoform_section
--- a/web/views/basecomponents.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/basecomponents.py	Thu Jan 10 18:34:10 2013 +0100
@@ -36,7 +36,7 @@
 from cubicweb.schema import display_name
 from cubicweb.utils import wrap_on_write
 from cubicweb.uilib import toggle_action
-from cubicweb.web import component, uicfg
+from cubicweb.web import component
 from cubicweb.web.htmlwidgets import MenuWidget, PopupBoxMenu
 
 VISIBLE_PROP_DEF = {
--- a/web/views/bookmark.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/bookmark.py	Thu Jan 10 18:34:10 2013 +0100
@@ -24,9 +24,8 @@
 
 from cubicweb import Unauthorized, typed_eid
 from cubicweb.predicates import is_instance, one_line_rset
-from cubicweb.web import (action, component, uicfg, htmlwidgets,
-                          formwidgets as fw)
-from cubicweb.web.views import primary
+from cubicweb.web import action, component, htmlwidgets, formwidgets as fw
+from cubicweb.web.views import uicfg, primary
 from cubicweb.web.views.ajaxcontroller import ajaxfunc
 
 _abaa = uicfg.actionbox_appearsin_addmenu
--- a/web/views/cwproperties.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/cwproperties.py	Thu Jan 10 18:34:10 2013 +0100
@@ -28,12 +28,12 @@
 from cubicweb.predicates import (one_line_rset, none_rset, is_instance,
                                  match_user_groups, logged_user_in_rset)
 from cubicweb.view import StartupView
-from cubicweb.web import uicfg, stdmsgs
+from cubicweb.web import stdmsgs
 from cubicweb.web.form import FormViewMixIn
 from cubicweb.web.formfields import FIELDS, StringField
 from cubicweb.web.formwidgets import (Select, TextInput, Button, SubmitButton,
                                       FieldWidget)
-from cubicweb.web.views import primary, formrenderers, editcontroller
+from cubicweb.web.views import uicfg, primary, formrenderers, editcontroller
 from cubicweb.web.views.ajaxcontroller import ajaxfunc
 
 uicfg.primaryview_section.tag_object_of(('*', 'for_user', '*'), 'hidden')
--- a/web/views/cwsources.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/cwsources.py	Thu Jan 10 18:34:10 2013 +0100
@@ -1,4 +1,4 @@
-# copyright 2010-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2010-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
 #
 # This file is part of CubicWeb.
@@ -33,9 +33,9 @@
                                 match_user_groups, match_kwargs, match_view)
 from cubicweb.view import EntityView, StartupView
 from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name
-from cubicweb.web import uicfg, formwidgets as wdgs, facet
+from cubicweb.web import formwidgets as wdgs, facet
 from cubicweb.web.views import add_etype_button
-from cubicweb.web.views import (tabs, actions, ibreadcrumbs, navigation,
+from cubicweb.web.views import (uicfg, tabs, actions, ibreadcrumbs, navigation,
                                 tableview, pyviews)
 
 
--- a/web/views/cwuser.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/cwuser.py	Thu Jan 10 18:34:10 2013 +0100
@@ -28,8 +28,8 @@
 from cubicweb.schema import display_name
 from cubicweb.predicates import one_line_rset, is_instance, match_user_groups
 from cubicweb.view import EntityView, StartupView
-from cubicweb.web import action, uicfg, formwidgets
-from cubicweb.web.views import tabs, tableview, actions, add_etype_button
+from cubicweb.web import action, formwidgets
+from cubicweb.web.views import uicfg, tabs, tableview, actions, add_etype_button
 
 _pvs = uicfg.primaryview_section
 _pvs.tag_attribute(('CWUser', 'login'), 'hidden')
--- a/web/views/editforms.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/editforms.py	Thu Jan 10 18:34:10 2013 +0100
@@ -34,10 +34,10 @@
                                 specified_etype_implements, is_instance)
 from cubicweb.view import EntityView
 from cubicweb.schema import display_name
-from cubicweb.web import uicfg, stdmsgs, eid_param, \
+from cubicweb.web import stdmsgs, eid_param, \
      formfields as ff, formwidgets as fw
 from cubicweb.web.form import FormViewMixIn, FieldNotFound
-from cubicweb.web.views import forms, reledit
+from cubicweb.web.views import uicfg, forms, reledit
 
 _pvdc = uicfg.primaryview_display_ctrl
 
--- a/web/views/emailaddress.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/emailaddress.py	Thu Jan 10 18:34:10 2013 +0100
@@ -24,8 +24,7 @@
 from cubicweb.schema import display_name
 from cubicweb.predicates import is_instance
 from cubicweb import Unauthorized
-from cubicweb.web import uicfg
-from cubicweb.web.views import baseviews, primary, ibreadcrumbs
+from cubicweb.web.views import uicfg, baseviews, primary, ibreadcrumbs
 
 _pvs = uicfg.primaryview_section
 _pvs.tag_subject_of(('*', 'use_email', '*'), 'attributes')
--- a/web/views/forms.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/forms.py	Thu Jan 10 18:34:10 2013 +0100
@@ -56,7 +56,8 @@
 from cubicweb.utils import support_args
 from cubicweb.predicates import non_final_entity, match_kwargs, one_line_rset
 from cubicweb.web import RequestError, ProcessFormError
-from cubicweb.web import uicfg, form, formwidgets as fwdgs
+from cubicweb.web import form, formwidgets as fwdgs
+from cubicweb.web.views import uicfg
 from cubicweb.web.formfields import guess_field
 
 
--- a/web/views/primary.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/primary.py	Thu Jan 10 18:34:10 2013 +0100
@@ -50,7 +50,8 @@
 from cubicweb.predicates import match_kwargs, match_context
 from cubicweb.view import EntityView
 from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name
-from cubicweb.web import uicfg, component
+from cubicweb.web import component
+from cubicweb.web.views import uicfg
 
 
 class PrimaryView(EntityView):
--- a/web/views/reledit.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/reledit.py	Thu Jan 10 18:34:10 2013 +0100
@@ -34,7 +34,8 @@
 from cubicweb.utils import json, json_dumps
 from cubicweb.predicates import non_final_entity, match_kwargs
 from cubicweb.view import EntityView
-from cubicweb.web import uicfg, stdmsgs
+from cubicweb.web import stdmsgs
+from cubicweb.web.views import uicfg
 from cubicweb.web.form import FieldNotFound
 from cubicweb.web.formwidgets import Button, SubmitButton
 from cubicweb.web.views.ajaxcontroller import ajaxfunc
--- a/web/views/schema.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/schema.py	Thu Jan 10 18:34:10 2013 +0100
@@ -39,9 +39,9 @@
 from cubicweb.utils import make_uid
 from cubicweb.view import EntityView, StartupView
 from cubicweb import tags, uilib
-from cubicweb.web import action, facet, uicfg, schemaviewer
+from cubicweb.web import action, facet, schemaviewer
 from cubicweb.web.views import TmpFileViewMixin
-from cubicweb.web.views import primary, baseviews, tabs, tableview, ibreadcrumbs
+from cubicweb.web.views import uicfg, primary, baseviews, tabs, tableview, ibreadcrumbs
 
 ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES
 SKIP_TYPES  = (ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES | WORKFLOW_TYPES
--- a/web/views/startup.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/startup.py	Thu Jan 10 18:34:10 2013 +0100
@@ -31,7 +31,8 @@
 from cubicweb.view import StartupView
 from cubicweb.predicates import match_user_groups, is_instance
 from cubicweb.schema import display_name
-from cubicweb.web import uicfg, httpcache
+from cubicweb.web import httpcache
+from cubicweb.web.views import uicfg
 
 class ManageView(StartupView):
     """:__regid__: *manage*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/uicfg.py	Thu Jan 10 18:34:10 2013 +0100
@@ -0,0 +1,436 @@
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
+"""This module (``cubicweb.web.uicfg``) regroups a set of structures that may be
+used to configure various options of the generated web interface.
+
+To configure the interface generation, we use ``RelationTag`` objects.
+
+Index view configuration
+````````````````````````
+:indexview_etype_section:
+   entity type category in the index/manage page. May be one of:
+
+      * ``application``
+      * ``system``
+      * ``schema``
+      * ``subobject`` (not displayed by default)
+
+   By default only entities on the ``application`` category are shown.
+
+.. sourcecode:: python
+
+    from cubicweb.web import uicfg
+    # force hiding
+    uicfg.indexview_etype_section['HideMe'] = 'subobject'
+    # force display
+    uicfg.indexview_etype_section['ShowMe'] = 'application'
+
+
+Actions box configuration
+`````````````````````````
+:actionbox_appearsin_addmenu:
+  simple boolean relation tags used to control the "add entity" submenu.
+  Relations whose rtag is True will appears, other won't.
+
+.. sourcecode:: python
+
+   # Adds all subjects of the entry_of relation in the add menu of the ``Blog``
+   # primary view
+   uicfg.actionbox_appearsin_addmenu.tag_object_of(('*', 'entry_of', 'Blog'), True)
+"""
+__docformat__ = "restructuredtext en"
+
+from warnings import warn
+
+from logilab.common.compat import any
+
+from cubicweb import neg_role
+from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet,
+                            RelationTagsDict, NoTargetRelationTagsDict,
+                            register_rtag, _ensure_str_key)
+from cubicweb.schema import META_RTYPES, INTERNAL_TYPES, WORKFLOW_TYPES
+
+
+# primary view configuration ##################################################
+
+def init_primaryview_section(rtag, sschema, rschema, oschema, role):
+    if rtag.get(sschema, rschema, oschema, role) is None:
+        rdef = rschema.rdef(sschema, oschema)
+        if rschema.final:
+            if rschema.meta or sschema.is_metadata(rschema) \
+                    or oschema.type in ('Password', 'Bytes'):
+                section = 'hidden'
+            else:
+                section = 'attributes'
+        else:
+            if rdef.role_cardinality(role) in '1+':
+                section = 'attributes'
+            elif rdef.composite == neg_role(role):
+                section = 'relations'
+            else:
+                section = 'sideboxes'
+        rtag.tag_relation((sschema, rschema, oschema, role), section)
+
+primaryview_section = RelationTags('primaryview_section',
+                                   init_primaryview_section,
+                                   frozenset(('attributes', 'relations',
+                                              'sideboxes', 'hidden')))
+
+
+class DisplayCtrlRelationTags(NoTargetRelationTagsDict):
+    def __init__(self, *args, **kwargs):
+        super(DisplayCtrlRelationTags, self).__init__(*args, **kwargs)
+        self.counter = 0
+
+def init_primaryview_display_ctrl(rtag, sschema, rschema, oschema, role):
+    if role == 'subject':
+        oschema = '*'
+    else:
+        sschema = '*'
+    rtag.counter += 1
+    rtag.setdefault((sschema, rschema, oschema, role), 'order', rtag.counter)
+
+primaryview_display_ctrl = DisplayCtrlRelationTags('primaryview_display_ctrl',
+                                                   init_primaryview_display_ctrl)
+
+
+# index view configuration ####################################################
+# entity type section in the index/manage page. May be one of
+# * 'application'
+# * 'system'
+# * 'schema'
+# * 'hidden'
+# * 'subobject' (not displayed by default)
+
+class InitializableDict(dict):
+    def __init__(self, *args, **kwargs):
+        super(InitializableDict, self).__init__(*args, **kwargs)
+        register_rtag(self)
+        self.__defaults = dict(self)
+
+    def init(self, schema, check=True):
+        self.update(self.__defaults)
+        for eschema in schema.entities():
+            if eschema.final:
+                continue
+            if eschema.schema_entity():
+                self.setdefault(eschema, 'schema')
+            elif eschema in INTERNAL_TYPES or eschema in WORKFLOW_TYPES:
+                self.setdefault(eschema, 'system')
+            elif eschema.is_subobject(strict=True):
+                self.setdefault(eschema, 'subobject')
+            else:
+                self.setdefault(eschema, 'application')
+
+indexview_etype_section = InitializableDict(
+    EmailAddress='subobject',
+    Bookmark='system',
+    # entity types in the 'system' table by default (managers only)
+    CWUser='system', CWGroup='system',
+    )
+
+# autoform.AutomaticEntityForm configuration ##################################
+
+def _formsections_as_dict(formsections):
+    result = {}
+    for formsection in formsections:
+        formtype, section = formsection.split('_', 1)
+        result[formtype] = section
+    return result
+
+def _card_and_comp(sschema, rschema, oschema, role):
+    rdef = rschema.rdef(sschema, oschema)
+    if role == 'subject':
+        card = rdef.cardinality[0]
+        composed = not rschema.final and rdef.composite == 'object'
+    else:
+        card = rdef.cardinality[1]
+        composed = not rschema.final and rdef.composite == 'subject'
+    return card, composed
+
+class AutoformSectionRelationTags(RelationTagsSet):
+    """autoform relations'section"""
+
+    _allowed_form_types = ('main', 'inlined', 'muledit')
+    _allowed_values = {'main': ('attributes', 'inlined', 'relations',
+                                'metadata', 'hidden'),
+                       'inlined': ('attributes', 'inlined', 'hidden'),
+                       'muledit': ('attributes', 'hidden'),
+                       }
+
+    def init(self, schema, check=True):
+        super(AutoformSectionRelationTags, self).init(schema, check)
+        self.apply(schema, self._initfunc_step2)
+
+    @staticmethod
+    def _initfunc(self, sschema, rschema, oschema, role):
+        formsections = self.init_get(sschema, rschema, oschema, role)
+        if formsections is None:
+            formsections = self.tag_container_cls()
+        if not any(tag.startswith('inlined') for tag in formsections):
+            if not rschema.final:
+                negsects = self.init_get(sschema, rschema, oschema, neg_role(role))
+                if 'main_inlined' in negsects:
+                    formsections.add('inlined_hidden')
+        key = _ensure_str_key( (sschema, rschema, oschema, role) )
+        self._tagdefs[key] = formsections
+
+    @staticmethod
+    def _initfunc_step2(self, sschema, rschema, oschema, role):
+        formsections = self.get(sschema, rschema, oschema, role)
+        sectdict = _formsections_as_dict(formsections)
+        if rschema in META_RTYPES:
+            sectdict.setdefault('main', 'hidden')
+            sectdict.setdefault('muledit', 'hidden')
+            sectdict.setdefault('inlined', 'hidden')
+        elif role == 'subject' and rschema in sschema.meta_attributes():
+            # meta attribute, usually embeded by the described attribute's field
+            # (eg RichTextField, FileField...)
+            sectdict.setdefault('main', 'hidden')
+            sectdict.setdefault('muledit', 'hidden')
+            sectdict.setdefault('inlined', 'hidden')
+        # ensure we have a tag for each form type
+        if not 'main' in sectdict:
+            if not rschema.final and (
+                sectdict.get('inlined') == 'attributes' or
+                'inlined_attributes' in self.init_get(sschema, rschema, oschema,
+                                                      neg_role(role))):
+                sectdict['main'] = 'hidden'
+            elif sschema.is_metadata(rschema):
+                sectdict['main'] = 'metadata'
+            else:
+                card, composed = _card_and_comp(sschema, rschema, oschema, role)
+                if card in '1+':
+                    sectdict['main'] = 'attributes'
+                    if not 'muledit' in sectdict:
+                        sectdict['muledit'] = 'attributes'
+                elif rschema.final:
+                    sectdict['main'] = 'attributes'
+                else:
+                    sectdict['main'] = 'relations'
+        if not 'muledit' in sectdict:
+            sectdict['muledit'] = 'hidden'
+            if sectdict['main'] == 'attributes':
+                card, composed = _card_and_comp(sschema, rschema, oschema, role)
+                if card in '1+' and not composed:
+                    sectdict['muledit'] = 'attributes'
+        if not 'inlined' in sectdict:
+            sectdict['inlined'] = sectdict['main']
+        # recompute formsections and set it to avoid recomputing
+        for formtype, section in sectdict.iteritems():
+            formsections.add('%s_%s' % (formtype, section))
+
+    def tag_relation(self, key, formtype, section):
+        if isinstance(formtype, tuple):
+            for ftype in formtype:
+                self.tag_relation(key, ftype, section)
+            return
+        assert formtype in self._allowed_form_types, \
+               'formtype should be in (%s), not %s' % (
+            ','.join(self._allowed_form_types), formtype)
+        assert section in self._allowed_values[formtype], \
+               'section for %s should be in (%s), not %s' % (
+            formtype, ','.join(self._allowed_values[formtype]), section)
+        rtags = self._tagdefs.setdefault(_ensure_str_key(key),
+                                         self.tag_container_cls())
+        # remove previous section for this form type if any
+        if rtags:
+            for tag in rtags.copy():
+                if tag.startswith(formtype):
+                    rtags.remove(tag)
+        rtags.add('%s_%s' % (formtype, section))
+        return rtags
+
+    def init_get(self, stype, rtype, otype, tagged):
+        key = (stype, rtype, otype, tagged)
+        rtags = {}
+        for key in self._get_keys(stype, rtype, otype, tagged):
+            tags = self._tagdefs.get(key, ())
+            for tag in tags:
+                assert '_' in tag, (tag, tags)
+                section, value = tag.split('_', 1)
+                rtags[section] = value
+        cls = self.tag_container_cls
+        rtags = cls('_'.join([section,value]) for section,value in rtags.iteritems())
+        return rtags
+
+
+    def get(self, *key):
+        # overriden to avoid recomputing done in parent classes
+        return self._tagdefs.get(key, ())
+
+    def relations_by_section(self, entity, formtype, section, permission,
+                             strict=False):
+        """return a list of (relation schema, target schemas, role) for the
+        given entity matching categories and permission.
+
+        `strict`:
+          bool telling if having local role is enough (strict = False) or not
+        """
+        tag = '%s_%s' % (formtype, section)
+        eschema  = entity.e_schema
+        permsoverrides = autoform_permissions_overrides
+        if entity.has_eid():
+            eid = entity.eid
+        else:
+            eid = None
+            strict = False
+        if permission == 'update':
+            assert section in ('attributes', 'metadata', 'hidden')
+            relpermission = 'add'
+        else:
+            assert section not in ('attributes', 'metadata', 'hidden')
+            relpermission = permission
+        cw = entity._cw
+        for rschema, targetschemas, role in eschema.relation_definitions(True):
+            _targetschemas = []
+            for tschema in targetschemas:
+                # check section's tag first, potentially lower cost than
+                # checking permission which may imply rql queries
+                if not tag in self.etype_get(eschema, rschema, role, tschema):
+                    continue
+                rdef = rschema.role_rdef(eschema, tschema, role)
+                if rschema.final:
+                    if not rdef.has_perm(cw, permission, eid=eid,
+                                         creating=eid is None):
+                        continue
+                elif strict or not rdef.has_local_role(relpermission):
+                    if role == 'subject':
+                        if not rdef.has_perm(cw, relpermission, fromeid=eid):
+                            continue
+                    elif role == 'object':
+                        if not rdef.has_perm(cw, relpermission, toeid=eid):
+                            continue
+                _targetschemas.append(tschema)
+            if not _targetschemas:
+                continue
+            targetschemas = _targetschemas
+            rdef = eschema.rdef(rschema, role=role, targettype=targetschemas[0])
+            # XXX tag allowing to hijack the permission machinery when
+            # permission is not verifiable until the entity is actually
+            # created...
+            if eid is None and '%s_on_new' % permission in permsoverrides.etype_get(eschema, rschema, role):
+                yield (rschema, targetschemas, role)
+                continue
+            if not rschema.final and role == 'subject':
+                # on relation with cardinality 1 or ?, we need delete perm as well
+                # if the relation is already set
+                if (relpermission == 'add'
+                    and rdef.role_cardinality(role) in '1?'
+                    and eid and entity.related(rschema.type, role)
+                    and not rdef.has_perm(cw, 'delete', fromeid=eid,
+                                          toeid=entity.related(rschema.type, role)[0][0])):
+                    continue
+            elif role == 'object':
+                # on relation with cardinality 1 or ?, we need delete perm as well
+                # if the relation is already set
+                if (relpermission == 'add'
+                    and rdef.role_cardinality(role) in '1?'
+                    and eid and entity.related(rschema.type, role)
+                    and not rdef.has_perm(cw, 'delete', toeid=eid,
+                                          fromeid=entity.related(rschema.type, role)[0][0])):
+                    continue
+            yield (rschema, targetschemas, role)
+
+autoform_section = AutoformSectionRelationTags('autoform_section')
+
+# relations'field class
+autoform_field = RelationTags('autoform_field')
+
+# relations'field explicit kwargs (given to field's __init__)
+autoform_field_kwargs = RelationTagsDict('autoform_field_kwargs')
+
+
+# set of tags of the form <action>_on_new on relations. <action> is a
+# schema action (add/update/delete/read), and when such a tag is found
+# permissions checking is by-passed and supposed to be ok
+autoform_permissions_overrides = RelationTagsSet('autoform_permissions_overrides')
+
+class ReleditTags(NoTargetRelationTagsDict):
+    """Associate to relation a dictionary to control `reledit` (e.g. edition of
+    attributes / relations from within views).
+
+    Possible keys and associated values are:
+
+    * `novalue_label`, alternative default value (shown when there is no value).
+
+    * `novalue_include_rtype`, when `novalue_label` is not specified, this boolean
+      flag control wether the generated default value should contains the
+      relation label or not. Will be the opposite of the `showlabel` value found
+      in the `primaryview_display_ctrl` rtag by default.
+
+    * `reload`, boolean, eid (to reload to) or function taking subject and
+      returning bool/eid. This is useful when editing a relation (or attribute)
+      that impacts the url or another parts of the current displayed
+      page. Defaults to False.
+
+    * `rvid`, alternative view id (as str) for relation or composite edition.
+      Default is 'autolimited'.
+
+    * `edit_target`, may be either 'rtype' (to edit the relation) or 'related'
+      (to edit the related entity).  This controls whether to edit the relation
+      or the target entity of the relation.  Currently only one-to-one relations
+      support target entity edition. By default, the 'related' option is taken
+      whenever the relation is composite.
+    """
+    _keys = frozenset('novalue_label novalue_include_rtype reload rvid edit_target'.split())
+
+    def tag_relation(self, key, tag):
+        for tagkey in tag.iterkeys():
+            assert tagkey in self._keys, 'tag %r not in accepted tags: %r' % (tag, self._keys)
+        return super(ReleditTags, self).tag_relation(key, tag)
+
+def init_reledit_ctrl(rtag, sschema, rschema, oschema, role):
+    values = rtag.get(sschema, rschema, oschema, role)
+    if not rschema.final:
+        composite = rschema.rdef(sschema, oschema).composite == role
+        if role == 'subject':
+            oschema = '*'
+        else:
+            sschema = '*'
+        edittarget = values.get('edit_target')
+        if edittarget not in (None, 'rtype', 'related'):
+            rtag.warning('reledit: wrong value for edit_target on relation %s: %s',
+                         rschema, edittarget)
+            edittarget = None
+        if not edittarget:
+            edittarget = 'related' if composite else 'rtype'
+            rtag.tag_relation((sschema, rschema, oschema, role),
+                              {'edit_target': edittarget})
+    if not 'novalue_include_rtype' in values:
+        showlabel = primaryview_display_ctrl.get(
+            sschema, rschema, oschema, role).get('showlabel', True)
+        rtag.tag_relation((sschema, rschema, oschema, role),
+                          {'novalue_include_rtype': not showlabel})
+
+reledit_ctrl = ReleditTags('reledit', init_reledit_ctrl)
+
+# boxes.EditBox configuration #################################################
+
+# 'link' / 'create' relation tags, used to control the "add entity" submenu
+def init_actionbox_appearsin_addmenu(rtag, sschema, rschema, oschema, role):
+    if rtag.get(sschema, rschema, oschema, role) is None:
+        if rschema in META_RTYPES:
+            rtag.tag_relation((sschema, rschema, oschema, role), False)
+            return
+        rdef = rschema.rdef(sschema, oschema)
+        if not rdef.role_cardinality(role) in '?1' and rdef.composite == role:
+            rtag.tag_relation((sschema, rschema, oschema, role), True)
+
+actionbox_appearsin_addmenu = RelationTagsBool('actionbox_appearsin_addmenu',
+                                               init_actionbox_appearsin_addmenu)
--- a/web/views/workflow.py	Thu Jan 10 13:03:38 2013 +0100
+++ b/web/views/workflow.py	Thu Jan 10 18:34:10 2013 +0100
@@ -36,10 +36,10 @@
                                 score_entity, is_instance, adaptable)
 from cubicweb.view import EntityView
 from cubicweb.schema import display_name
-from cubicweb.web import uicfg, stdmsgs, action, component, form, action
+from cubicweb.web import stdmsgs, action, component, form, action
 from cubicweb.web import formfields as ff, formwidgets as fwdgs
 from cubicweb.web.views import TmpFileViewMixin
-from cubicweb.web.views import forms, primary, ibreadcrumbs
+from cubicweb.web.views import uicfg, forms, primary, ibreadcrumbs
 from cubicweb.web.views.tabs import TabbedPrimaryView, PrimaryTab
 from cubicweb.web.views.dotgraphview import DotGraphView, DotPropsHandler