# HG changeset patch # User sylvain.thenault@logilab.fr # Date 1242122172 -7200 # Node ID 78b0819162a8e41da970185c36a0f09daf5713ca # Parent 2cfd50c8a415755fa71f15d34432ae70c8b8c275 final rtag api diff -r 2cfd50c8a415 -r 78b0819162a8 devtools/devctl.py --- a/devtools/devctl.py Tue May 12 11:49:30 2009 +0200 +++ b/devtools/devctl.py Tue May 12 11:56:12 2009 +0200 @@ -163,7 +163,8 @@ subjtype, objtype = teschema, eschema if librschema.has_rdef(subjtype, objtype): continue - if actionbox.relation_mode(rschema, eschema, teschema, role) == 'create': + if actionbox.appearsin_addmenu.etype_get(eschema, rschema, + role, teschema): if role == 'subject': label = 'add %s %s %s %s' % (eschema, rschema, teschema, role) diff -r 2cfd50c8a415 -r 78b0819162a8 entity.py --- a/entity.py Tue May 12 11:49:30 2009 +0200 +++ b/entity.py Tue May 12 11:56:12 2009 +0200 @@ -50,11 +50,13 @@ def _dispatch_rtags(tags, rtype, role, stype, otype): for tag in tags: if tag in _MODE_TAGS: - uicfg.rmode.tag_relation(stype, rtype, otype, tag, role) + uicfg.actionbox_appearsin_addmenu.tag_relation( + (stype, rtype, otype, role), tag == 'create') elif tag in _CATEGORY_TAGS: - uicfg.rcategories.tag_relation(stype, rtype, otype, tag, role) + uicfg.autoform_section.tag_relation((stype, rtype, otype, role), + tag) elif tag == 'inlineview': - uicfg.rinlined.tag_relation(stype, rtype, otype, True, role) + uicfg.autoform_is_inlined.tag_relation((stype, rtype, otype, role), True) else: raise ValueError(tag) @@ -128,8 +130,8 @@ wdgname = 'TextInput' widget = getattr(formwidgets, wdgname) assert hasattr(widget, 'render') - uicfg.rwidgets.tag_relation( - etype, rtype, '*', widget, tagged='subject') + uicfg.autoform_widget.tag_subject_of((etype, rtype, '*'), + widget) return super(_metaentity, mcs).__new__(mcs, name, bases, classdict) diff -r 2cfd50c8a415 -r 78b0819162a8 rtags.py --- a/rtags.py Tue May 12 11:49:30 2009 +0200 +++ b/rtags.py Tue May 12 11:56:12 2009 +0200 @@ -16,9 +16,12 @@ This class associates a single tag to each key. """ - - def __init__(self): + _allowed_values = None + def __init__(self, initfunc=None, allowed_values=None): self._tagdefs = {} + if allowed_values is not None: + self._allowed_values = allowed_values + self._initfunc = initfunc def __repr__(self): return repr(self._tagdefs) @@ -28,24 +31,7 @@ return self.get(*key) __contains__ = __getitem__ - def _get_tagged(self, stype, otype, tagged=None): - stype, otype = str(stype), str(otype) - if tagged is None: - if stype[0] == '!': - tagged = 'subject' - stype = stype[1:] - elif otype[0] == '!': - tagged = 'object' - otype = otype[1:] - else: - raise AssertionError('either stype or rtype should have the ' - 'role mark ("!")') - else: - assert tagged in ('subject', 'object'), repr(tagged) - return stype, otype, tagged - - def _get_keys(self, stype, rtype, otype, tagged=None): - stype, otype, tagged = self._get_tagged(stype, otype, tagged) + def _get_keys(self, stype, rtype, otype, tagged): keys = [(rtype, tagged, '*', '*'), (rtype, tagged, '*', otype), (rtype, tagged, stype, '*'), @@ -58,18 +44,56 @@ keys.remove((rtype, tagged, stype, '*')) return keys - def tag_relation(self, stype, rtype, otype, tag, tagged=None): - stype, otype, tagged = self._get_tagged(stype, otype, tagged) - self._tagdefs[(str(rtype), tagged, stype, otype)] = tag + def init(self, schema): + # XXX check existing keys against schema + for rtype, tagged, stype, otype in self._tagdefs: + assert rtype in schema + if stype != '*': + assert stype in schema + if otype != '*': + assert otype in schema + if self._initfunc is not None: + for eschema in schema.entities(): + for rschema, tschemas, role in eschema.relation_definitions(True): + for tschema in tschemas: + if role == 'subject': + stype, otype = eschema, tschema + else: + stype, otype = tschema, eschema + self._initfunc(stype, rtype, otype, role) + + # rtag declaration api #################################################### + + def tag_attribute(self, key, tag): + key = list(key) + key.append('*') + self.tag_subject_of(key, tag) - def tag_attribute(self, stype, attr, tag): - self.tag_relation(stype, attr, '*', tag, 'subject') + def tag_subject_of(self, key, tag): + key = list(key) + key.append('subject') + self.tag_relation(key, tag) + + def tag_object_of(self, key, tag): + key = list(key) + key.append('object') + self.tag_relation(key, tag) - def del_rtag(self, stype, rtype, otype): - stype, otype, tagged = self._get_tagged(stype, otype) - del self._tagdefs[(str(rtype), tagged, stype, otype)] + def tag_relation(self, key, tag): + #if isinstance(key, basestring): + # stype, rtype, otype = key.split() + #else: + stype, rtype, otype, tagged = [str(k) for k in key] + if self._allowed_values is not None: + assert tag in self._allowed_values + self._tagdefs[(rtype, tagged, stype, otype)] = tag - def get(self, stype, rtype, otype, tagged=None): + # rtag runtime api ######################################################## + + def del_rtag(self, stype, rtype, otype, tagged): + del self._tagdefs[(rtype, tagged, stype, otype)] + + def get(self, stype, rtype, otype, tagged): for key in reversed(self._get_keys(stype, rtype, otype, tagged)): try: return self._tagdefs[key] @@ -87,12 +111,12 @@ class RelationTagsSet(RelationTags): """This class associates a set of tags to each key.""" - def tag_relation(self, stype, rtype, otype, tag, tagged=None): - stype, otype, tagged = self._get_tagged(stype, otype, tagged) + def tag_relation(self, key, tag): + stype, rtype, otype, tagged = [str(k) for k in key] rtags = self._tagdefs.setdefault((rtype, tagged, stype, otype), set()) rtags.add(tag) - def get(self, stype, rtype, otype, tagged=None): + def get(self, stype, rtype, otype, tagged): rtags = set() for key in self._get_keys(stype, rtype, otype, tagged): try: @@ -100,3 +124,16 @@ except KeyError: continue return rtags + + +class RelationTagsBool(RelationTags): + _allowed_values = frozenset((True, False)) + + def tag_subject_of(self, key, tag=True): + super(RelationTagsBool, self).tag_subject_of(key, tag) + + def tag_object_of(self, key, tag=True): + super(RelationTagsBool, self).tag_object_of(key, tag) + + def tag_attribute(self, key, tag=True): + super(RelationTagsBool, self).tag_attribute(key, tag) diff -r 2cfd50c8a415 -r 78b0819162a8 test/unittest_rtags.py --- a/test/unittest_rtags.py Tue May 12 11:49:30 2009 +0200 +++ b/test/unittest_rtags.py Tue May 12 11:56:12 2009 +0200 @@ -5,22 +5,20 @@ def test_rtags_expansion(self): rtags = RelationTags() - rtags.tag_relation('!Societe', 'travaille', '*', 'primary') - rtags.tag_relation('!*', 'evaluee', '*', 'secondary') - rtags.tag_relation('*', 'tags', '!*', 'generated') - self.assertEquals(rtags.get('!Note', 'evaluee', '*'), - 'secondary') + rtags.tag_subject_of(('Societe', 'travaille', '*'), 'primary') + rtags.tag_subject_of(('*', 'evaluee', '*'), 'secondary') + rtags.tag_object_of(('*', 'tags', '*'), 'generated') self.assertEquals(rtags.get('Note', 'evaluee', '*', 'subject'), 'secondary') - self.assertEquals(rtags.get('!Societe', 'travaille', '*'), + self.assertEquals(rtags.get('Societe', 'travaille', '*', 'subject'), 'primary') - self.assertEquals(rtags.get('!Note', 'travaille', '*'), + self.assertEquals(rtags.get('Note', 'travaille', '*', 'subject'), None) - self.assertEquals(rtags.get('!Note', 'tags', '*'), + self.assertEquals(rtags.get('Note', 'tags', '*', 'subject'), None) - self.assertEquals(rtags.get('*', 'tags', '!Note'), + self.assertEquals(rtags.get('*', 'tags', 'Note', 'object'), 'generated') - self.assertEquals(rtags.get('Tag', 'tags', '!*'), + self.assertEquals(rtags.get('Tag', 'tags', '*', 'object'), 'generated') # self.assertEquals(rtags.rtag('evaluee', 'Note', 'subject'), set(('secondary', 'link'))) @@ -44,15 +42,15 @@ def test_rtagset_expansion(self): rtags = RelationTagsSet() - rtags.tag_relation('!Societe', 'travaille', '*', 'primary') - rtags.tag_relation('!*', 'travaille', '*', 'secondary') - self.assertEquals(rtags.get('!Societe', 'travaille', '*'), + rtags.tag_subject_of(('Societe', 'travaille', '*'), 'primary') + rtags.tag_subject_of(('*', 'travaille', '*'), 'secondary') + self.assertEquals(rtags.get('Societe', 'travaille', '*', 'subject'), set(('primary', 'secondary'))) self.assertEquals(rtags.get('Societe', 'travaille', '*', 'subject'), set(('primary', 'secondary'))) - self.assertEquals(rtags.get('!Note', 'travaille', '*'), + self.assertEquals(rtags.get('Note', 'travaille', '*', 'subject'), set(('secondary',))) - self.assertEquals(rtags.get('!Note', 'tags', "*"), + self.assertEquals(rtags.get('Note', 'tags', "*", 'subject'), set()) if __name__ == '__main__': diff -r 2cfd50c8a415 -r 78b0819162a8 web/test/unittest_form.py --- a/web/test/unittest_form.py Tue May 12 11:49:30 2009 +0200 +++ b/web/test/unittest_form.py Tue May 12 11:56:12 2009 +0200 @@ -1,7 +1,8 @@ from logilab.common.testlib import unittest_main, mock_object from cubicweb import Binary from cubicweb.devtools.testlib import WebTest -from cubicweb.web.form import EntityFieldsForm, FieldsForm, FormRenderer +from cubicweb.web.form import EntityFieldsForm, FieldsForm +from cubicweb.web.formrenderers import FormRenderer from cubicweb.web.formfields import (IntField, StringField, RichTextField, DateTimeField, DateTimePicker, FileField, EditableFileField) diff -r 2cfd50c8a415 -r 78b0819162a8 web/test/unittest_views_editforms.py --- a/web/test/unittest_views_editforms.py Tue May 12 11:49:30 2009 +0200 +++ b/web/test/unittest_views_editforms.py Tue May 12 11:56:12 2009 +0200 @@ -9,7 +9,8 @@ class AutomaticEntityFormTC(EnvBasedTC): def test_custom_widget(self): - AEF.rwidgets.tag_relation('!CWUser', 'login', '*', AutoCompletionWidget) + AEF.rwidgets.tag_subject_of(('CWUser', 'login', '*'), + AutoCompletionWidget) form = self.vreg.select_object('forms', 'edition', self.request(), None, entity=self.user()) field = form.field_by_name('login') diff -r 2cfd50c8a415 -r 78b0819162a8 web/uicfg.py --- a/web/uicfg.py Tue May 12 11:49:30 2009 +0200 +++ b/web/uicfg.py Tue May 12 11:56:12 2009 +0200 @@ -1,127 +1,267 @@ -"""schema driven ui configuration. +# :organization: Logilab +# :copyright: 2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +"""This module regroups a set of structures that may be used to configure +various places of the generated web interface. + +Primary view configuration +`````````````````````````` +:primaryview_section: + where to display a relation in primary view. Value may be one of: + * 'attributes', display in the attributes section + * 'relations', display in the relations section (below attributes) + * 'sideboxes', display in the side boxes (beside attributes) + * 'hidden', don't display + +:primaryview_display_ctrl: + + how to display a relation in primary view. Values are dict with some of the + following keys: + + :vid: + identifier of a view to use to display the result set. Defaults depends on + the section: + * 'attributes' section: 'reledit' view + * 'relations' section: 'autolimited' view + * 'sideboxes' section: 'sidebox' view + + :label: + label for the relations section or side box -set of properties configuring edition, actions box, ... rendering using tags -on schema relations. Those properties are defined here so we don't get module -reloading problems. + :limit: + boolean telling if the results should be limited according to the + configuration + + :filter: + callback taking the related result set as argument and returning it + filtered + + :order: + int used to control order within a section. When not specified, + automatically set according to order in which tags are added. + + Notice those values are only considered if the relation is in a displayed + section (controlled by :attr:`primaryview_section`) + -:organization: Logilab -:copyright: 2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. -:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +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) + + +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. + +Automatic form configuration +```````````````````````````` + """ __docformat__ = "restructuredtext en" -from cubicweb.rtags import RelationTags, RelationTagsSet +from cubicweb.rtags import RelationTags, RelationTagsBool, RelationTagsSet +from cubicweb.web import formwidgets # primary view configuration ################################################## -# how to display a relation in primary view. -# values a dict with the following keys: -# -# 'where', whose value may be one of: -# * 'attributes', display in the attributes section -# * 'relations', display in the relations section (below attributes) -# * 'sideboxes', display in the side boxes (beside attributes) -# if this key is missing, the relation won't be displayed at all. -# -# 'vid' is an optional view identifier -# -# 'label' is an optional label -# -# 'limit' is a boolean telling if the results should be limited according to -# the configuration -class RDisplayRelationTags(RelationTags): - def __init__(self): - super(RDisplayRelationTags, self).__init__() - self._counter = 0 +def init_primaryview_section(self, sschema, rschema, oschema, role): + if self.get(sschema, rschema, oschema, role) is None: + if rschema.is_final(): + if rschema.meta or tschema.type in ('Password', 'Bytes'): + section = 'hidden' + else: + section = 'attributes' + elif card in '1+': + section = 'attributes' + elif composed: + section = 'relations' + else: + section = 'sideboxes' + self.tag_relation((sschema, rschema, oschema, role), section) - def tag_relation(self, stype, rtype, otype, tag, tagged=None): - super(RDisplayRelationTags, self).tag_relation(stype, rtype, otype, tag, - tagged) - if tag: - tag['order'] = self.get_timestamp() - - def get_timestamp(self): - self._counter += 1 - return self._counter - -rdisplay = RDisplayRelationTags() +primaryview_section = RelationTags(init_primaryview_section, + frozenset(('attributes', 'relations', + 'sideboxes', 'hidden'))) for rtype in ('eid', 'creation_date', 'modification_date', 'is', 'is_instance_of', 'identity', 'owned_by', 'created_by', 'in_state', 'wf_info_for', 'require_permission', 'from_entity', 'to_entity', 'see_also'): - rdisplay.tag_relation('!*', rtype, '*', {}) - rdisplay.tag_relation('*', rtype, '!*', {}) + primaryview_section.tag_subject_of(('*', rtype, '*'), 'hidden') + primaryview_section.tag_object_of(('*', rtype, '*'), 'hidden') + +for attr in ('name', 'meta', 'final'): + primaryview_section.tag_attribute(('CWEType', attr), 'hidden') +for attr in ('name', 'meta', 'final', 'symetric', 'inlined'): + primaryview_section.tag_attribute(('CWRType', attr), 'hidden') + + +class DisplayCtrlRelationTags(RelationTags): + def __init__(self, *args, **kwargs): + super(DisplayCtrlRelationTags, self).__init__(*args, **kwargs) + self._counter = 0 + + def tag_relation(self, key, tag): + assert isinstance(tag, dict) + super(RDisplayRelationTags, self).tag_relation(key, tag) + self._counter += 1 + tag.setdefault('order', self._counter) + + +def init_primaryview_display_ctrl(self, sschema, rschema, oschema, role): + if role == 'subject': + oschema = '*' + label = rschema.type + else: + sschema = '*' + label = '%s_%s' % (rschema, role) + displayinfo = self.get(sschema, rschema, oschema, role) + if displayinfo is None: + displayinfo = {} + self.tag_relation((sschema, rschema, oschema, role), displayinfo) + displayinfo.setdefault('label', label) + +primaryview_display_ctrl = DisplayCtrlRelationTags(init_primaryview_display_ctrl) # index view configuration #################################################### -# entity type category in the index/manage page. May be one of +# entity type section in the index/manage page. May be one of # * 'application' # * 'system' # * 'schema' # * 'subobject' (not displayed by default) -etypecat = {'EmailAddress': 'subobject'} +indexview_etype_section = {'EmailAddress': 'subobject'} # autoform.AutomaticEntityForm configuration ################################## -# relations'category (eg primary/secondary/generic/metadata/generated) -rcategories = RelationTags() -# use primary and not generated for eid since it has to be an hidden -rcategories.tag_attribute('*', 'eid', 'primary') -rcategories.tag_attribute('*', 'description', 'secondary') -rcategories.tag_attribute('*', 'creation_date', 'metadata') -rcategories.tag_attribute('*', 'modification_date', 'metadata') -rcategories.tag_attribute('*', 'has_text', 'generated') +# relations'section (eg primary/secondary/generic/metadata/generated) + +def init_autoform_section(self, sschema, rschema, oschema, role): + if self.get(sschema, rschema, oschema, role) is None: + if role == 'subject': + card = rschema.rproperty(sschema, oschema, 'cardinality')[0] + composed = rschema.rproperty(sschema, oschema, 'composite') == 'object' + else: + card = rschema.rproperty(sschema, oschema, 'cardinality')[1] + composed = rschema.rproperty(sschema, oschema, 'composite') == 'subject' + if sschema.is_metadata(rschema): + section = 'generated' + elif card in '1+': + if not rschema.is_final() and composed: + section = 'generated' + else: + section = 'primary' + elif rschema.is_final(): + section = 'secondary' + else: + section = 'generic' + self.tag_relation((sschema, rschema, oschema, role), section) -rcategories.tag_relation('!*', 'in_state', '*', 'primary') -rcategories.tag_relation('!*', 'owned_by', '*', 'metadata') -rcategories.tag_relation('!*', 'created_by', '*', 'metadata') -rcategories.tag_relation('!*', 'is', '*', 'generated') -rcategories.tag_relation('*', 'is', '!*', 'generated') -rcategories.tag_relation('!*', 'is_instance_of', '*', 'generated') -rcategories.tag_relation('*', 'is_instance_of', '!*', 'generated') -rcategories.tag_relation('!*', 'identity', '*', 'generated') -rcategories.tag_relation('*', 'identity', '!*', 'generated') -rcategories.tag_relation('!*', 'require_permission', '*', 'generated') -rcategories.tag_relation('!*', 'wf_info_for', '*', 'generated') -rcategories.tag_relation('*', 'wf_info_for', '!*', 'generated') -rcategories.tag_relation('!*', 'for_user', '*', 'generated') -rcategories.tag_relation('*', 'for_user', '!*', 'generated') +autoform_section = RelationTags(init_autoform_section, + set(('primary', 'secondary', 'generic', + 'metadata', 'generated'))) +# use primary and not generated for eid since it has to be an hidden +autoform_section.tag_attribute(('*', 'eid'), 'primary') +autoform_section.tag_attribute(('*', 'description'), 'secondary') +autoform_section.tag_attribute(('*', 'creation_date'), 'metadata') +autoform_section.tag_attribute(('*', 'modification_date'), 'metadata') +autoform_section.tag_attribute(('*', 'has_text'), 'generated') +autoform_section.tag_subject_of(('*', 'in_state', '*'), 'primary') +autoform_section.tag_subject_of(('*', 'owned_by', '*'), 'metadata') +autoform_section.tag_subject_of(('*', 'created_by', '*'), 'metadata') +autoform_section.tag_subject_of(('*', 'is', '*'), 'generated') +autoform_section.tag_object_of(('* ', 'is', '*'), 'generated') +autoform_section.tag_subject_of(('*', 'is_instance_of', '*'), 'generated') +autoform_section.tag_object_of(('* ', 'is_instance_of', '*'), 'generated') +autoform_section.tag_subject_of(('*', 'identity', '*'), 'generated') +autoform_section.tag_object_of(('* ', 'identity', '*'), 'generated') +autoform_section.tag_subject_of(('*', 'require_permission', '*'), 'generated') +autoform_section.tag_subject_of(('*', 'wf_info_for', '*'), 'generated') +autoform_section.tag_object_of(('* ', 'wf_info_for', '*'), 'generated') +autoform_section.tag_subject_of(('*', 'for_user', '*'), 'generated') +autoform_section.tag_object_of(('* ', 'for_user', '*'), 'generated') +autoform_section.tag_subject_of(('CWPermission', 'require_group', '*'), 'primary') +autoform_section.tag_attribute(('EEtype', 'final'), 'generated') +autoform_section.tag_attribute(('ERtype', 'final'), 'generated') +autoform_section.tag_attribute(('CWUser', 'firstname'), 'secondary') +autoform_section.tag_attribute(('CWUser', 'surname'), 'secondary') +autoform_section.tag_attribute(('CWUser', 'last_login_time'), 'metadata') +autoform_section.tag_subject_of(('CWUser', 'in_group', '*'), 'primary') +autoform_section.tag_object_of(('*', 'owned_by', 'CWUser'), 'generated') +autoform_section.tag_object_of(('*', 'created_by', 'CWUser'), 'generated') +autoform_section.tag_object_of(('*', 'bookmarked_by', 'CWUser'), 'metadata') +autoform_section.tag_attribute(('Bookmark', 'path'), 'primary') + # relations'field class -rfields = RelationTags() +autoform_field = RelationTags() # relations'widget class -rwidgets = RelationTags() +autoform_widget = RelationTags() +autoform_widget.tag_attribute(('RQLExpression', 'expression'), + formwidgets.TextInput) +autoform_widget.tag_attribute(('Bookmark', 'path'), formwidgets.TextInput) + + # inlined view flag for non final relations: when True for an entry, the # entity(ies) at the other end of the relation will be editable from the # form of the edited entity -rinlined = RelationTags() -rinlined.tag_relation('!*', 'use_email', '*', True) +autoform_is_inlined = RelationTagsBool() +autoform_is_inlined.tag_subject_of(('*', 'use_email', '*'), True) +autoform_is_inlined.tag_subject_of(('CWRelation', 'relation_type', '*'), True) +autoform_is_inlined.tag_subject_of(('CWRelation', 'from_entity', '*'), True) +autoform_is_inlined.tag_subject_of(('CWRelation', 'to_entity', '*'), True) # set of tags of the form _on_new on relations. 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 -rpermissions_overrides = RelationTagsSet() +autoform_permissions_overrides = RelationTagsSet() # boxes.EditBox configuration ################################################# # 'link' / 'create' relation tags, used to control the "add entity" submenu -rmode = RelationTags() -rmode.tag_relation('!*', 'is', '*', 'link') -rmode.tag_relation('*', 'is', '!*', 'link') -rmode.tag_relation('!*', 'is_instance_of', '*', 'link') -rmode.tag_relation('*', 'is_instance_of', '!*', 'link') -rmode.tag_relation('!*', 'identity', '*', 'link') -rmode.tag_relation('*', 'identity', '!*', 'link') -rmode.tag_relation('!*', 'owned_by', '*', 'link') -rmode.tag_relation('!*', 'created_by', '*', 'link') -rmode.tag_relation('!*', 'require_permission', '*', 'link') -rmode.tag_relation('!*', 'wf_info_for', '*', 'link') -rmode.tag_relation('*', 'wf_info_for', '!*', 'link') +def init_actionbox_appearsin_addmenu(self, sschema, rschema, oschema, role): + if self.get(sschema, rschema, oschema, role) is None: + card = rschema.rproperty(sschema, oschema, 'cardinality')[role == 'object'] + if not card in '?1' and \ + rschema.rproperty(sschema, oschema, 'composite') == role: + self.tag_relation((sschema, rschema, oschema, role), True) + +actionbox_appearsin_addmenu = RelationTagsBool(init_actionbox_appearsin_addmenu) +actionbox_appearsin_addmenu.tag_subject_of(('*', 'is', '*'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'is', '*'), False) +actionbox_appearsin_addmenu.tag_subject_of(('*', 'is_instance_of', '*'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'is_instance_of', '*'), False) +actionbox_appearsin_addmenu.tag_subject_of(('*', 'identity', '*'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'identity', '*'), False) +actionbox_appearsin_addmenu.tag_subject_of(('*', 'owned_by', '*'), False) +actionbox_appearsin_addmenu.tag_subject_of(('*', 'created_by', '*'), False) +actionbox_appearsin_addmenu.tag_subject_of(('*', 'require_permission', '*'), False) +actionbox_appearsin_addmenu.tag_subject_of(('*', 'wf_info_for', '*'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'wf_info_for', '*'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'state_of', 'CWEType'), True) +actionbox_appearsin_addmenu.tag_object_of(('*', 'transition_of', 'CWEType'), True) +actionbox_appearsin_addmenu.tag_object_of(('*', 'relation_type', 'CWRType'), True) +actionbox_appearsin_addmenu.tag_object_of(('*', 'from_entity', 'CWEType'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'to_entity', 'CWEType'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'in_group', 'CWGroup'), True) +actionbox_appearsin_addmenu.tag_object_of(('*', 'owned_by', 'CWUser'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'created_by', 'CWUser'), False) +actionbox_appearsin_addmenu.tag_object_of(('*', 'bookmarked_by', 'CWUser'), True) +actionbox_appearsin_addmenu.tag_subject_of(('Transition', 'destination_state', '*'), True) +actionbox_appearsin_addmenu.tag_object_of(('*', 'allowed_transition', 'Transition'), True) +actionbox_appearsin_addmenu.tag_object_of(('*', 'destination_state', 'State'), True) +actionbox_appearsin_addmenu.tag_subject_of(('State', 'allowed_transition', '*'), True) diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/autoform.py --- a/web/views/autoform.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/autoform.py Tue May 12 11:56:12 2009 +0200 @@ -38,45 +38,26 @@ attrcategories = ('primary', 'secondary') # class attributes below are actually stored in the uicfg module since we # don't want them to be reloaded - rcategories = uicfg.rcategories - rfields = uicfg.rfields - rwidgets = uicfg.rwidgets - rinlined = uicfg.rinlined - rpermissions_overrides = uicfg.rpermissions_overrides + rcategories = uicfg.autoform_section + rfields = uicfg.autoform_field + rwidgets = uicfg.autoform_widget + rinlined = uicfg.autoform_is_inlined + rpermissions_overrides = uicfg.autoform_permissions_overrides @classmethod def vreg_initialization_completed(cls): """set default category tags for relations where it's not yet defined in the category relation tags """ - for eschema in cls.schema.entities(): - for rschema, tschemas, role in eschema.relation_definitions(True): - for tschema in tschemas: - if role == 'subject': - X, Y = eschema, tschema - card = rschema.rproperty(X, Y, 'cardinality')[0] - composed = rschema.rproperty(X, Y, 'composite') == 'object' - else: - X, Y = tschema, eschema - card = rschema.rproperty(X, Y, 'cardinality')[1] - composed = rschema.rproperty(X, Y, 'composite') == 'subject' - if not cls.rcategories.get(X, rschema, Y, role): - if eschema.is_metadata(rschema): - category = 'generated' - elif card in '1+': - if not rschema.is_final() and composed: - category = 'generated' - else: - category = 'primary' - elif rschema.is_final(): - category = 'secondary' - else: - category = 'generic' - cls.rcategories.tag_relation(X, rschema, Y, category, - tagged=role) + cls.rcategories.init(cls.schema) + cls.rfields.init(cls.schema) + cls.rwidgets.init(cls.schema) + cls.rinlined.init(cls.schema) + cls.rpermissions_overrides.init(cls.schema) @classmethod - def erelations_by_category(cls, entity, categories=None, permission=None, rtags=None): + def erelations_by_category(cls, entity, categories=None, permission=None, + rtags=None): """return a list of (relation schema, target schemas, role) matching categories and permission """ diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/basecomponents.py --- a/web/views/basecomponents.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/basecomponents.py Tue May 12 11:56:12 2009 +0200 @@ -14,7 +14,7 @@ from cubicweb.selectors import yes, two_etypes_rset, match_form_params from cubicweb.schema import display_name from cubicweb.common.uilib import html_escape, toggle_action -from cubicweb.web import uicfg, component +from cubicweb.web import component from cubicweb.web.htmlwidgets import (MenuWidget, PopupBoxMenu, BoxSeparator, BoxLink) @@ -145,15 +145,14 @@ """display the application name""" id = 'appliname' property_defs = VISIBLE_PROP_DEF + # don't want user to hide this component using an cwproperty + site_wide = True def call(self): - self.w(u'%s' % (self.req.base_url(), - self.req.property_value('ui.site-title'))) + self.w(u'%s' % ( + self.req.base_url(), self.req.property_value('ui.site-title'))) -uicfg.rdisplay.tag_relation('!*', 'see_also', '*', {}) -uicfg.rdisplay.tag_relation('*', 'see_also', '!*', {}) - class SeeAlsoVComponent(component.RelatedObjectsVComponent): """display any entity's see also""" id = 'seealso' diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/bookmark.py --- a/web/views/bookmark.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/bookmark.py Tue May 12 11:56:12 2009 +0200 @@ -11,12 +11,9 @@ from cubicweb import Unauthorized from cubicweb.selectors import implements from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, RawBoxItem -from cubicweb.web import uicfg, action, box, formwidgets +from cubicweb.web import action, box from cubicweb.web.views import primary -uicfg.rcategories.tag_attribute('!Bookmark', 'path', 'primary') -uicfg.rwidgets.tag_attribute('Bookmark', 'path', formwidgets.TextInput) - class FollowAction(action.Action): id = 'follow' diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/boxes.py --- a/web/views/boxes.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/boxes.py Tue May 12 11:56:12 2009 +0200 @@ -37,41 +37,14 @@ order = 2 # class attributes below are actually stored in the uicfg module since we # don't want them to be reloaded - rmode = uicfg.rmode + appearsin_addmenu = uicfg.actionbox_appearsin_addmenu @classmethod def vreg_initialization_completed(cls): """set default category tags for relations where it's not yet defined in the category relation tags """ - for eschema in cls.schema.entities(): - for rschema, tschemas, role in eschema.relation_definitions(True): - for tschema in tschemas: - if role == 'subject': - X, Y = eschema, tschema - card = rschema.rproperty(X, Y, 'cardinality')[0] - else: - X, Y = tschema, eschema - card = rschema.rproperty(X, Y, 'cardinality')[1] - if not cls.rmode.get(X, rschema, Y, role): - if card in '?1': - # by default, suppose link mode if cardinality doesn't allow - # more than one relation - mode = 'link' - elif rschema.rproperty(X, Y, 'composite') == role: - # if self is composed of the target type, create mode - mode = 'create' - else: - # link mode by default - mode = 'link' - cls.rmode.tag_relation(X, rschema, Y, mode, tagged=role) - - @classmethod - def relation_mode(cls, rtype, etype, targettype, role='subject'): - """return a string telling if the given relation is usually created - to a new entity ('create' mode) or to an existant entity ('link' mode) - """ - return cls.rmode.etype_get(etype, rtype, role, targettype) + cls.appearsin_addmenu.init(cls.schema) def call(self, view=None, **kwargs): _ = self.req._ @@ -157,13 +130,17 @@ if rschema.is_final(): continue # check the relation can be added as well - if role == 'subject'and not rschema.has_perm(req, 'add', fromeid=entity.eid): + # XXX consider autoform_permissions_overrides? + if role == 'subject'and not rschema.has_perm(req, 'add', + fromeid=entity.eid): continue - if role == 'object'and not rschema.has_perm(req, 'add', toeid=entity.eid): + if role == 'object'and not rschema.has_perm(req, 'add', + toeid=entity.eid): continue # check the target types can be added as well for teschema in rschema.targets(eschema, role): - if not self.relation_mode(rschema, eschema, teschema, role) == 'create': + if not self.appearsin_addmenu.etype_get(eschema, rschema, + role, teschema): continue if teschema.has_local_role('add') or teschema.has_perm(req, 'add'): yield rschema, teschema, role diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/cwproperties.py --- a/web/views/cwproperties.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/cwproperties.py Tue May 12 11:56:12 2009 +0200 @@ -339,5 +339,5 @@ self.widget = wdg -uicfg.rfields.tag_attribute('CWProperty', 'pkey', PropertyKeyField) -uicfg.rfields.tag_attribute('CWProperty', 'value', PropertyValueField) +uicfg.autoform_field.tag_attribute(('CWProperty', 'pkey'), PropertyKeyField) +uicfg.autoform_field.tag_attribute(('CWProperty', 'value'), PropertyValueField) diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/cwuser.py --- a/web/views/cwuser.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/cwuser.py Tue May 12 11:56:12 2009 +0200 @@ -10,24 +10,10 @@ from cubicweb.selectors import one_line_rset, implements, match_user_groups from cubicweb.view import EntityView -from cubicweb.web import uicfg, action +from cubicweb.web import action from cubicweb.web.views import primary -uicfg.rcategories.tag_attribute('CWUser', 'firstname', 'secondary') -uicfg.rcategories.tag_attribute('CWUser', 'surname', 'secondary') -uicfg.rcategories.tag_attribute('CWUser', 'last_login_time', 'metadata') -uicfg.rcategories.tag_relation('!CWUser', 'in_group', '*', 'primary') -uicfg.rcategories.tag_relation('*', 'owned_by', '!CWUser', 'generated') -uicfg.rcategories.tag_relation('*', 'created_by', '!CWUser', 'generated') -uicfg.rcategories.tag_relation('*', 'bookmarked_by', '!CWUser', 'metadata') - -uicfg.rmode.tag_relation('*', 'in_group', '!CWGroup', 'create') -uicfg.rmode.tag_relation('*', 'owned_by', '!CWUser', 'link') -uicfg.rmode.tag_relation('*', 'created_by', '!CWUser', 'link') -uicfg.rmode.tag_relation('*', 'bookmarked_by', '!CWUser', 'create') - - class UserPreferencesEntityAction(action.Action): id = 'prefs' __select__ = (one_line_rset() & implements('CWUser') & diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/primary.py --- a/web/views/primary.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/primary.py Tue May 12 11:56:12 2009 +0200 @@ -5,6 +5,7 @@ :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" +_ = unicode from warnings import warn @@ -12,9 +13,8 @@ from cubicweb import Unauthorized from cubicweb.view import EntityView -from cubicweb.web.uicfg import rdisplay +from cubicweb.web import uicfg -_ = unicode class PrimaryView(EntityView): @@ -24,7 +24,8 @@ show_attr_label = True show_rel_label = True skip_none = True - rdisplay = rdisplay + rsection = uicfg.primaryview_section + display_ctrl = uicfg.primaryview_display_ctrl main_related_section = True @classmethod @@ -32,38 +33,8 @@ """set default category tags for relations where it's not yet defined in the category relation tags """ - for eschema in cls.schema.entities(): - for rschema, tschemas, role in eschema.relation_definitions(True): - for tschema in tschemas: - if role == 'subject': - X, Y = eschema, tschema - card = rschema.rproperty(X, Y, 'cardinality')[0] - composed = rschema.rproperty(X, Y, 'composite') == 'object' - else: - X, Y = tschema, eschema - card = rschema.rproperty(X, Y, 'cardinality')[1] - composed = rschema.rproperty(X, Y, 'composite') == 'subject' - displayinfo = cls.rdisplay.get(X, rschema, Y, role) - if displayinfo is None: - if rschema.is_final(): - if rschema.meta or tschema.type in ('Password', 'Bytes'): - where = None - else: - where = 'attributes' - elif card in '1+': - where = 'attributes' - elif composed: - where = 'relations' - else: - where = 'sideboxes' - displayinfo = {'where': where, - 'order': cls.rdisplay.get_timestamp()} - cls.rdisplay.tag_relation(X, rschema, Y, displayinfo, - tagged=role) - if role == 'subject': - displayinfo.setdefault('label', rschema.type) - else: - displayinfo.setdefault('label', '%s_%s' % (rschema, role)) + cls.rsection.init(cls.schema) + cls.display_ctrl.init(cls.schema) def html_headers(self): """return a list of html headers (eg something to be inserted between @@ -150,12 +121,12 @@ return u'' def render_entity_attributes(self, entity, siderelations=None): - for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'attributes'): - vid = displayinfo.get('vid', 'reledit') + for rschema, tschemas, role, dispctrl in self._section_def(entity, 'attributes'): + vid = dispctrl.get('vid', 'reledit') if rschema.is_final() or vid == 'reledit': value = entity.view(vid, rtype=rschema.type, role=role) else: - rset = self._relation_rset(entity, rschema, role, displayinfo) + rset = self._relation_rset(entity, rschema, role, dispctrl) if rset: value = self.view(vid, rset) else: @@ -165,10 +136,10 @@ self._render_attribute(rschema, value) def render_entity_relations(self, entity, siderelations=None): - for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'relations'): - rset = self._relation_rset(entity, rschema, role, displayinfo) + for rschema, tschemas, role, dispctrl in self._section_def(entity, 'relations'): + rset = self._relation_rset(entity, rschema, role, dispctrl) if rset: - self._render_relation(rset, displayinfo, 'autolimited', + self._render_relation(rset, dispctrl, 'autolimited', self.show_rel_label) def render_side_boxes(self, boxes): @@ -177,7 +148,7 @@ """ for box in boxes: if isinstance(box, tuple): - label, rset, vid, _ = box + label, rset, vid = box self.w(u'
') self.wview(vid, rset, title=label) self.w(u'
') @@ -191,52 +162,54 @@ def _prepare_side_boxes(self, entity): sideboxes = [] - for rschema, tschemas, role, displayinfo in self._iter_display(entity, 'sideboxes'): - rset = self._relation_rset(entity, rschema, role, displayinfo) + for rschema, tschemas, role, dispctrl in self._section_def(entity, 'sideboxes'): + rset = self._relation_rset(entity, rschema, role, dispctrl) if not rset: continue label = display_name(self.req, rschema.type, role) - vid = displayinfo.get('vid', 'autolimited') - sideboxes.append((label, rset, vid, displayinfo.get('order'))) - sideboxes = sorted(sideboxes, key=lambda x: x[-1]) - sideboxes += list(self.vreg.possible_vobjects('boxes', self.req, self.rset, - row=self.row, view=self, - context='incontext')) + vid = dispctrl.get('vid', 'sidebox') + sideboxes.append( (label, rset, vid) ) + sideboxes += self.vreg.possible_vobjects('boxes', self.req, self.rset, + row=self.row, view=self, + context='incontext') return sideboxes - def _iter_display(self, entity, where): + def _section_def(self, entity, where): + rdefs = [] eschema = entity.e_schema for rschema, tschemas, role in eschema.relation_definitions(True): matchtschemas = [] for tschema in tschemas: - displayinfo = self.rdisplay.etype_get(eschema, rschema, role, - tschema) - assert displayinfo is not None, (str(rschema), role, - str(eschema), str(tschema)) - if displayinfo.get('where') == where: + section = self.rsection.etype_get(eschema, rschema, role, + tschema) + if section == where: matchtschemas.append(tschema) if matchtschemas: - # XXX pick the latest displayinfo - yield rschema, matchtschemas, role, displayinfo + # XXX pick the latest dispctrl + dispctrl = self.display_ctrl.etype_get(eschema, rschema, role, + matchtschemas[-1]) - def _relation_rset(self, entity, rschema, role, displayinfo): + rdefs.append( (rschema, matchtschemas, role, dispctrl) ) + return sorted(rdefs, key=lambda x: x[-1]['order']) + + def _relation_rset(self, entity, rschema, role, dispctrl): try: - if displayinfo.get('limit'): + if dispctrl.get('limit'): rset = entity.related(rschema.type, role, limit=self.maxrelated+1) else: rset = entity.related(rschema.type, role) except Unauthorized: return - if 'filter' in displayinfo: - rset = displayinfo['filter'](rset) + if 'filter' in dispctrl: + rset = dispctrl['filter'](rset) return rset - def _render_relation(self, rset, displayinfo, defaultvid, showlabel): + def _render_relation(self, rset, dispctrl, defaultvid, showlabel): self.w(u'
') if showlabel: - self.w(u'

%s

' % self.req._(displayinfo['label'])) - self.wview(displayinfo.get('vid', defaultvid), rset) + self.w(u'

%s

' % self.req._(dispctrl['label'])) + self.wview(dispctrl.get('vid', defaultvid), rset) self.w(u'
') def _render_attribute(self, rschema, value, role='subject'): diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/schema.py --- a/web/views/schema.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/schema.py Tue May 12 11:56:12 2009 +0200 @@ -15,32 +15,10 @@ from cubicweb.schemaviewer import SchemaViewer from cubicweb.view import EntityView, StartupView from cubicweb.common import tags, uilib -from cubicweb.web import uicfg, formwidgets, action +from cubicweb.web import action from cubicweb.web.views import TmpFileViewMixin, primary, baseviews -uicfg.rcategories.tag_relation('!CWPermission', 'require_group', '*', 'primary') -uicfg.rcategories.tag_attribute('EEtype', 'final', 'generated') -uicfg.rcategories.tag_attribute('ERtype', 'final', 'generated') - -uicfg.rinlined.tag_relation('!CWRelation', 'relation_type', '*', True) -uicfg.rinlined.tag_relation('!CWRelation', 'from_entity', '*', True) -uicfg.rinlined.tag_relation('!CWRelation', 'to_entity', '*', True) - -uicfg.rwidgets.tag_attribute('RQLExpression', 'expression', formwidgets.TextInput) - -uicfg.rmode.tag_relation('*', 'state_of', '!CWEType', 'create') -uicfg.rmode.tag_relation('*', 'transition_of', '!CWEType', 'create') -uicfg.rmode.tag_relation('*', 'relation_type', '!CWRType', 'create') -uicfg.rmode.tag_relation('*', 'from_entity', '!CWEType', 'link') -uicfg.rmode.tag_relation('*', 'to_entity', '!CWEType', 'link') - -for attr in ('name', 'meta', 'final'): - uicfg.rdisplay.tag_attribute('CWRType', attr, {}) -for attr in ('name', 'meta', 'final', 'symetric', 'inlined'): - uicfg.rdisplay.tag_attribute('CWRType', attr, {}) - - class ViewSchemaAction(action.Action): id = 'schema' __select__ = yes() diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/startup.py --- a/web/views/startup.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/startup.py Tue May 12 11:56:12 2009 +0200 @@ -27,13 +27,13 @@ def vreg_initialization_completed(cls): for eschema in cls.schema.entities(): if eschema.schema_entity(): - uicfg.etypecat.setdefault(eschema, 'schema') + uicfg.indexview_etype_section.setdefault(eschema, 'schema') elif eschema.is_subobject(strict=True): - uicfg.etypecat.setdefault(eschema, 'subobject') + uicfg.indexview_etype_section.setdefault(eschema, 'subobject') elif eschema.meta: - uicfg.etypecat.setdefault(eschema, 'system') + uicfg.indexview_etype_section.setdefault(eschema, 'system') else: - uicfg.etypecat.setdefault(eschema, 'application') + uicfg.indexview_etype_section.setdefault(eschema, 'application') def display_folders(self): return False @@ -100,15 +100,15 @@ if manager: self.w(u'%s\n' % self.req._('application entities')) self.entity_types_table(eschema for eschema in schema.entities() - if uicfg.etypecat.get(eschema) == 'application') + if uicfg.indexview_etype_section.get(eschema) == 'application') if manager: self.w(u'%s\n' % self.req._('system entities')) self.entity_types_table(eschema for eschema in schema.entities() - if uicfg.etypecat.get(eschema) == 'system') + if uicfg.indexview_etype_section.get(eschema) == 'system') if 'CWAttribute' in schema: # check schema support self.w(u'%s\n' % self.req._('schema entities')) self.entity_types_table(eschema for eschema in schema.entities() - if uicfg.etypecat.get(eschema) == 'schema') + if uicfg.indexview_etype_section.get(eschema) == 'schema') self.w(u'') def entity_types_table(self, eschemas): diff -r 2cfd50c8a415 -r 78b0819162a8 web/views/workflow.py --- a/web/views/workflow.py Tue May 12 11:49:30 2009 +0200 +++ b/web/views/workflow.py Tue May 12 11:56:12 2009 +0200 @@ -8,6 +8,7 @@ :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr """ __docformat__ = "restructuredtext en" +_ = unicode from logilab.mtconverter import html_escape from logilab.common.graph import escape, GraphGenerator, DotBackend @@ -23,13 +24,6 @@ from cubicweb.web.views import TmpFileViewMixin from cubicweb.web.views.boxes import EditBox -_ = unicode - -EditBox.rmode.tag_relation('!Transition', 'destination_state', '*', 'create') -EditBox.rmode.tag_relation('*', 'allowed_transition', '!Transition', 'create') -EditBox.rmode.tag_relation('*', 'destination_state', '!State', 'create') -EditBox.rmode.tag_relation('!State', 'allowed_transition', '*', 'create') - # IWorkflowable views #########################################################