backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 10 Feb 2012 16:53:52 +0100
changeset 8216 99ff746e8de8
parent 8214 ce9556358dbd (current diff)
parent 8215 4b32678c21a7 (diff)
child 8218 0725e3b81442
backport stable
__pkginfo__.py
devtools/fake.py
entities/wfobjs.py
entity.py
hooks/syncschema.py
pylintext.py
server/migractions.py
server/serverconfig.py
test/unittest_entity.py
view.py
web/views/primary.py
web/views/schema.py
web/views/tabs.py
web/views/workflow.py
--- a/.hgtags	Fri Feb 10 16:31:39 2012 +0100
+++ b/.hgtags	Fri Feb 10 16:53:52 2012 +0100
@@ -241,3 +241,5 @@
 6928210da4fc25d086b5b8d5ff2029da41aade2e cubicweb-debian-version-3.14.1-1
 049a3819f03dc79d803be054cc3bfe8425313f63 cubicweb-version-3.14.2
 17ebd836cee30a9f690e83af7ce98287a7216d57 cubicweb-debian-version-3.14.2-1
+60efdbb455204899103c30bfa8d805c1b15161f6 cubicweb-version-3.14.3
+4d0f5d18e8a07ab218efe90d758af723ea4a1b2b cubicweb-debian-version-3.14.3-1
--- a/debian/changelog	Fri Feb 10 16:31:39 2012 +0100
+++ b/debian/changelog	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,9 @@
+cubicweb (3.14.3-1) unstable; urgency=low
+
+  * new upstream release
+
+ -- Sylvain Thénault <sylvain.thenault@logilab.fr>  Fri, 03 Feb 2012 16:53:54 +0100
+
 cubicweb (3.14.2-1) unstable; urgency=low
 
   * new upstream release
--- a/devtools/fake.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/devtools/fake.py	Fri Feb 10 16:53:52 2012 +0100
@@ -42,7 +42,7 @@
         self['auth-mode'] = 'cookie'
         self['uid'] = None
         self['base-url'] = BASE_URL
-        self['rql-cache-size'] = 100
+        self['rql-cache-size'] = 3000
         self.datadir_url = BASE_URL + 'data/'
 
     def cubes(self, expand=False):
--- a/entities/wfobjs.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/entities/wfobjs.py	Fri Feb 10 16:53:52 2012 +0100
@@ -256,6 +256,9 @@
     """customized class for Transition entities"""
     __regid__ = 'Transition'
 
+    def dc_long_title(self):
+        return '%s (%s)' % (self.name, self._cw._(self.name))
+
     def destination(self, entity):
         try:
             return self.destination_state[0]
@@ -345,6 +348,9 @@
     fetch_attrs, cw_fetch_order = fetch_config(['name'])
     rest_attr = 'eid'
 
+    def dc_long_title(self):
+        return '%s (%s)' % (self.name, self._cw._(self.name))
+
     @property
     def workflow(self):
         # take care, may be missing in multi-sources configuration
--- a/entity.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/entity.py	Fri Feb 10 16:53:52 2012 +0100
@@ -481,7 +481,9 @@
             assert eschema.has_relation(attr, role), '%s %s not found on %s' % (attr, role, eschema)
             rschema = eschema.subjrels[attr] if role == 'subject' else eschema.objrels[attr]
             if not rschema.final and isinstance(value, (tuple, list, set, frozenset)):
-                if len(value) == 1:
+                if len(value) == 0:
+                    continue # avoid crash with empty IN clause
+                elif len(value) == 1:
                     value = iter(value).next()
                 else:
                     # prepare IN clause
--- a/etwist/service.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/etwist/service.py	Fri Feb 10 16:53:52 2012 +0100
@@ -25,9 +25,12 @@
     print 'Win32 extensions for Python are likely not installed.'
     sys.exit(3)
 
+from os.path import join
 
 from cubicweb.etwist.server import (CubicWebRootResource, reactor, server)
 
+from logilab.common.shellutils import rm
+
 import logging
 from logging import getLogger, handlers
 from cubicweb import set_log_methods
@@ -74,6 +77,9 @@
             config.init_log(force=True)
             config.debugmode = False
             logger.info('starting cubicweb instance %s ', self.instance)
+            config.info('clear ui caches')
+            for cachedir in ('uicache', 'uicachehttps'):
+                rm(join(config.appdatahome, cachedir, '*'))
             root_resource = CubicWebRootResource(config)
             website = server.Site(root_resource)
             # serve it via standard HTTP on port set in the configuration
--- a/hooks/syncschema.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/hooks/syncschema.py	Fri Feb 10 16:53:52 2012 +0100
@@ -268,9 +268,8 @@
             try:
                 rschema = schema[rtype]
             except KeyError:
-                if rtype == 'cw_source':
-                    continue # XXX 3.10 migration
-                raise
+                self.critical('rtype %s was not handled at cwetype creation time', rtype)
+                continue
             sampletype = rschema.subjects()[0]
             desttype = rschema.objects()[0]
             rdef = copy(rschema.rdef(sampletype, desttype))
@@ -493,7 +492,7 @@
                     default = syssource.dbhelper.sql_current_date()
                 elif default == 'NOW':
                     default = syssource.dbhelper.sql_current_timestamp()
-                session.system_sql('UPDATE %s SET %s=%(default)s'
+                session.system_sql('UPDATE %s SET %s=%s'
                                    % (table, column, default))
             else:
                 session.system_sql('UPDATE %s SET %s=%%(default)s' % (table, column),
--- a/i18n/de.po	Fri Feb 10 16:31:39 2012 +0100
+++ b/i18n/de.po	Fri Feb 10 16:53:52 2012 +0100
@@ -1435,6 +1435,9 @@
 msgid "click to edit this field"
 msgstr "Klicken Sie, um dieses Feld zu editieren"
 
+msgid "close all"
+msgstr ""
+
 msgid "comment"
 msgstr "Kommentar"
 
--- a/i18n/en.po	Fri Feb 10 16:31:39 2012 +0100
+++ b/i18n/en.po	Fri Feb 10 16:53:52 2012 +0100
@@ -1389,6 +1389,9 @@
 msgid "click to edit this field"
 msgstr ""
 
+msgid "close all"
+msgstr ""
+
 msgid "comment"
 msgstr ""
 
--- a/i18n/es.po	Fri Feb 10 16:31:39 2012 +0100
+++ b/i18n/es.po	Fri Feb 10 16:53:52 2012 +0100
@@ -1447,6 +1447,9 @@
 msgid "click to edit this field"
 msgstr "seleccione para editar este campo"
 
+msgid "close all"
+msgstr ""
+
 msgid "comment"
 msgstr "Comentario"
 
--- a/i18n/fr.po	Fri Feb 10 16:31:39 2012 +0100
+++ b/i18n/fr.po	Fri Feb 10 16:53:52 2012 +0100
@@ -4,7 +4,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: cubicweb 2.46.0\n"
-"PO-Revision-Date: 2011-11-23 11:09+0100\n"
+"PO-Revision-Date: 2012-02-08 17:43+0100\n"
 "Last-Translator: Logilab Team <contact@logilab.fr>\n"
 "Language-Team: fr <contact@logilab.fr>\n"
 "Language: \n"
@@ -1449,6 +1449,9 @@
 msgid "click to edit this field"
 msgstr "cliquez pour éditer ce champ"
 
+msgid "close all"
+msgstr "tout fermer"
+
 msgid "comment"
 msgstr "commentaire"
 
@@ -2754,7 +2757,7 @@
 msgstr "chemin"
 
 msgid "i18n_login_popup"
-msgstr "s'authentifier"
+msgstr "s'identifier"
 
 msgid "i18ncard_*"
 msgstr "0..n"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.14.4_Any.py	Fri Feb 10 16:53:52 2012 +0100
@@ -0,0 +1,9 @@
+from yams import schema2sql as y2sql
+
+dbhelper = repo.system_source.dbhelper
+rdefdef = schema['CWSource'].rdef('name')
+attrtype = y2sql.type_from_constraints(dbhelper, rdefdef.object, rdefdef.constraints).split()[0]
+
+sql(dbhelper.sql_change_col_type('entities', 'asource', attrtype, False))
+sql(dbhelper.sql_change_col_type('entities', 'source', attrtype, False))
+sql(dbhelper.sql_change_col_type('deleted_entities', 'source', attrtype, False))
--- a/pylintext.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/pylintext.py	Fri Feb 10 16:53:52 2012 +0100
@@ -35,7 +35,7 @@
         for etype in BASE_TYPES:
             module.locals[etype] = [scoped_nodes.Class(etype, None)]
     # add data() to uiprops module
-    if module.name.endswith('.uiprops'):
+    if module.name.split('.')[-1] == 'uiprops':
         fake = ASTNGBuilder(MANAGER).string_build('''
 def data(string):
   return u''
--- a/server/migractions.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/server/migractions.py	Fri Feb 10 16:53:52 2012 +0100
@@ -1025,15 +1025,15 @@
 
         """
         reposchema = self.repo.schema
+        rschema = self.fs_schema.rschema(rtype)
+        execute = self._cw.execute
         if rtype in reposchema:
             print 'warning: relation type %s is already known, skip addition' % (
                 rtype)
-            return
-        rschema = self.fs_schema.rschema(rtype)
-        execute = self._cw.execute
-        # register the relation into CWRType and insert necessary relation
-        # definitions
-        ss.execschemarql(execute, rschema, ss.rschema2rql(rschema, addrdef=False))
+        else:
+            # register the relation into CWRType and insert necessary relation
+            # definitions
+            ss.execschemarql(execute, rschema, ss.rschema2rql(rschema, addrdef=False))
         if addrdef:
             self.commit()
             gmap = self.group_mapping()
--- a/server/serverconfig.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/server/serverconfig.py	Fri Feb 10 16:53:52 2012 +0100
@@ -136,7 +136,7 @@
           }),
         ('rql-cache-size',
          {'type' : 'int',
-          'default': 300,
+          'default': 3000,
           'help': 'size of the parsed rql cache size.',
           'group': 'main', 'level': 3,
           }),
--- a/server/sources/native.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/server/sources/native.py	Fri Feb 10 16:53:52 2012 +0100
@@ -1459,8 +1459,8 @@
 CREATE TABLE entities (
   eid INTEGER PRIMARY KEY NOT NULL,
   type VARCHAR(64) NOT NULL,
-  source VARCHAR(64) NOT NULL,
-  asource VARCHAR(64) NOT NULL,
+  source VARCHAR(128) NOT NULL,
+  asource VARCHAR(128) NOT NULL,
   mtime %s NOT NULL,
   extid VARCHAR(256)
 );;
@@ -1471,7 +1471,7 @@
 CREATE TABLE deleted_entities (
   eid INTEGER PRIMARY KEY NOT NULL,
   type VARCHAR(64) NOT NULL,
-  source VARCHAR(64) NOT NULL,
+  source VARCHAR(128) NOT NULL,
   dtime %s NOT NULL,
   extid VARCHAR(256)
 );;
--- a/skeleton/entities.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/entities.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright %(year)s %(author)s, all rights reserved.
 # contact %(author-web-site)s -- mailto:%(author-email)s
 #
--- a/skeleton/hooks.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/hooks.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright %(year)s %(author)s, all rights reserved.
 # contact %(author-web-site)s -- mailto:%(author-email)s
 #
--- a/skeleton/migration/postcreate.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/migration/postcreate.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright %(year)s %(author)s, all rights reserved.
 # contact %(author-web-site)s -- mailto:%(author-email)s
 #
--- a/skeleton/migration/precreate.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/migration/precreate.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright %(year)s %(author)s, all rights reserved.
 # contact %(author-web-site)s -- mailto:%(author-email)s
 #
--- a/skeleton/schema.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/schema.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright %(year)s %(author)s, all rights reserved.
 # contact %(author-web-site)s -- mailto:%(author-email)s
 #
--- a/skeleton/sobjects.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/sobjects.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright %(year)s %(author)s, all rights reserved.
 # contact %(author-web-site)s -- mailto:%(author-email)s
 #
--- a/skeleton/uiprops.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/uiprops.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 ###############################################################################
 #
 # Put here information about external resources / styles used by your cube,
--- a/skeleton/views.py.tmpl	Fri Feb 10 16:31:39 2012 +0100
+++ b/skeleton/views.py.tmpl	Fri Feb 10 16:53:52 2012 +0100
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 # copyright %(year)s %(author)s, all rights reserved.
 # contact %(author-web-site)s -- mailto:%(author-email)s
 #
--- a/test/unittest_entity.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/test/unittest_entity.py	Fri Feb 10 16:53:52 2012 +0100
@@ -146,6 +146,8 @@
         req = self.request()
         p1 = req.create_entity('Personne', nom=u'di')
         p2 = req.create_entity('Personne', nom=u'mascio')
+        t = req.create_entity('Tag', name=u't0', tags=[])
+        self.assertItemsEqual(t.tags, [])
         t = req.create_entity('Tag', name=u't1', tags=p1)
         self.assertItemsEqual(t.tags, [p1])
         t = req.create_entity('Tag', name=u't2', tags=p1.eid)
--- a/view.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/view.py	Fri Feb 10 16:53:52 2012 +0100
@@ -196,7 +196,7 @@
         """
         rset = self.cw_rset
         if rset is None:
-            raise NotImplementedError, (self, "an rset is required")
+            raise NotImplementedError("%r an rset is required" % self)
         wrap = self.templatable and len(rset) > 1 and self.add_div_section
         # avoid re-selection if rset of size 1, we already have the most
         # specific view
@@ -218,7 +218,7 @@
 
     def cell_call(self, row, col, **kwargs):
         """the view is called for a particular result set cell"""
-        raise NotImplementedError, self
+        raise NotImplementedError(repr(self))
 
     def linkable(self):
         """return True if the view may be linked in a menu
@@ -379,7 +379,7 @@
         self.entity_call(self.cw_rset.get_entity(row, col), **kwargs)
 
     def entity_call(self, entity, **kwargs):
-        raise NotImplementedError()
+        raise NotImplementedError('%r %r' % (self.__regid__, self.__class__))
 
 
 class StartupView(View):
--- a/web/data/cubicweb.ajax.js	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/data/cubicweb.ajax.js	Fri Feb 10 16:53:52 2012 +0100
@@ -709,6 +709,7 @@
 function loadNow(eltsel, holesel, reloadable) {
     var lazydiv = jQuery(eltsel);
     var hole = lazydiv.children(holesel);
+    hole.show();
     if ((hole.length == 0) && ! reloadable) {
         /* the hole is already filed */
         return;
--- a/web/data/cubicweb.edition.js	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/data/cubicweb.edition.js	Fri Feb 10 16:53:52 2012 +0100
@@ -474,7 +474,7 @@
         errmsg = descr;
     } else {
         _displayValidationerrors(formid, descr[0], descr[1]);
-        errmsg = _('please correct errors below');
+        errmsg = _("please correct errors below");
     }
     updateMessage(errmsg);
     // ensure the browser does not scroll down
--- a/web/data/cubicweb.facets.js	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/data/cubicweb.facets.js	Fri Feb 10 16:53:52 2012 +0100
@@ -181,11 +181,11 @@
                         $this.find('img').each(function(i) {
                             if (this.getAttribute('cubicweb:unselimg')) {
                                 this.setAttribute('src', UNSELECTED_BORDER_IMG);
-                                this.setAttribute('alt', (_('not selected')));
+                                this.setAttribute('alt', (_("not selected")));
                             }
                             else {
                                 this.setAttribute('src', UNSELECTED_IMG);
-                                this.setAttribute('alt', (_('not selected')));
+                                this.setAttribute('alt', (_("not selected")));
                             }
                         });
                         var index = parseInt($this.attr('cubicweb:idx'));
@@ -213,7 +213,7 @@
                         }
                         jQuery(this).addClass('facetValueSelected');
                         var $img = jQuery(this).find('img');
-                        $img.attr('src', SELECTED_IMG).attr('alt', (_('selected')));
+                        $img.attr('src', SELECTED_IMG).attr('alt', (_("selected")));
                     }
                     buildRQL.apply(null, jsfacetargs);
                     facet.find('.facetBody').animate({
--- a/web/data/cubicweb.preferences.js	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/data/cubicweb.preferences.js	Fri Feb 10 16:53:52 2012 +0100
@@ -11,13 +11,13 @@
 }
 
 function closeFieldset(fieldsetid) {
-    var linklabel = _('open all');
+    var linklabel = _("open all");
     var linkhref = 'javascript:openFieldset("' + fieldsetid + '")';
     _toggleFieldset(fieldsetid, 1, linklabel, linkhref);
 }
 
 function openFieldset(fieldsetid) {
-    var linklabel = _('close all');
+    var linklabel = _("close all");
     var linkhref = 'javascript:closeFieldset("' + fieldsetid + '")';
     _toggleFieldset(fieldsetid, 0, linklabel, linkhref);
 }
@@ -37,7 +37,7 @@
             fieldset.addClass('hidden');
         } else {
             fieldset.removeClass('hidden');
-            linkLabel = (_('open all'));
+            linkLabel = (_("open all"));
         }
     });
 }
--- a/web/formwidgets.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/formwidgets.py	Fri Feb 10 16:53:52 2012 +0100
@@ -429,7 +429,7 @@
     an unicode string, or a list of unicode strings.
     """
     vocabulary_widget = True
-    default_size = 5
+    default_size = 10
 
     def __init__(self, attrs=None, multiple=False, **kwargs):
         super(Select, self).__init__(attrs, **kwargs)
@@ -473,6 +473,74 @@
         return value in curvalues
 
 
+class InOutWidget(Select):
+    needs_js = ('cubicweb.widgets.js', )
+    default_size = 10
+    template = """
+<table id="%(widgetid)s">
+  <tr>
+    <td>%(inoutinput)s</td>
+    <td><div style="margin-bottom:3px">%(addinput)s</div>
+        <div>%(removeinput)s</div>
+    </td>
+    <td>%(resinput)s</td>
+  </tr>
+</table>
+"""
+    add_button = ('<input type="button" id="cwinoutadd" class="wdgButton cwinoutadd" '
+                  'value="&gt;&gt;" size="10" />')
+    remove_button = ('<input type="button" class="wdgButton cwinoutremove" '
+                     'value="&lt;&lt;" size="10" />')
+
+    def __init__(self, *args, **kwargs):
+        super(InOutWidget, self).__init__(*args, **kwargs)
+        self._multiple = True
+
+    def render_select(self, form, field, name, selected=False):
+        values, attrs = self.values_and_attributes(form, field)
+        options = []
+        inputs = []
+        for option in field.vocabulary(form):
+            try:
+                label, value, _oattrs = option
+            except ValueError:
+                label, value = option
+            if selected:
+                # add values
+                if value in values:
+                    options.append(tags.option(label, value=value))
+                    # add hidden inputs
+                    inputs.append(tags.input(value=value,
+                                             name=field.dom_id(form),
+                                             type="hidden"))
+            else:
+                options.append(tags.option(label, value=value))
+        if 'size' not in attrs:
+            attrs['size'] = self.default_size
+        if 'id' in attrs :
+            attrs.pop('id')
+        return tags.select(name=name, multiple=self._multiple, id=name,
+                           options=options, **attrs) + '\n'.join(inputs)
+
+
+    def _render(self, form, field, renderer):
+        domid = field.dom_id(form)
+        jsnodes = {'widgetid': domid,
+                   'from': 'from_' + domid,
+                   'to': 'to_' + domid}
+        form._cw.add_onload(u'$(cw.jqNode("%s")).cwinoutwidget("%s", "%s");'
+                            % (jsnodes['widgetid'], jsnodes['from'], jsnodes['to']))
+        field.required = True
+        return (self.template %
+                {'widgetid': jsnodes['widgetid'],
+                 # helpinfo select tag
+                 'inoutinput' : self.render_select(form, field, jsnodes['from']),
+                 # select tag with resultats
+                 'resinput' : self.render_select(form, field, jsnodes['to'], selected=True),
+                 'addinput' : self.add_button % jsnodes,
+                 'removeinput': self.remove_button % jsnodes
+                 })
+
 class BitSelect(Select):
     """Select widget for IntField using a vocabulary with bit masks as values.
 
@@ -1023,55 +1091,3 @@
             'label': label, 'imgsrc': imgsrc,
             'domid': self.domid, 'href': self.href}
 
-class InOutWidget(Select):
-    needs_js = ('cubicweb.widgets.js', )
-    template = """
-<table id="%(widgetid)s">
-<tr><td>%(inoutinput)s</td>
-    <td><div style="margin-bottom:3px">%(addinput)s</div> <div>%(removeinput)s</div></td>
-    <td>%(resinput)s</td></tr>
-</table>
-"""
-    add_button = """<input type="button" id="cwinoutadd"  class="wdgButton cwinoutadd" value="&gt;&gt;" size="10" />"""
-    remove_button ="""<input type="button" class="wdgButton cwinoutremove" value="&lt;&lt;" size="10" />"""
-
-    def __init__(self, attrs=None):
-        super(InOutWidget, self).__init__(attrs, multiple=True)
-
-    def render_select(self, form, field, name, selected=False):
-        values, attrs = self.values_and_attributes(form, field)
-        options = []
-        inputs = []
-        for _option in field.vocabulary(form):
-            try:
-                label, value, oattrs = _option
-            except ValueError:
-                label, value = _option
-            if selected:
-                # add values
-                if value in values:
-                    options.append(tags.option(label, value=value))
-                    # add hidden inputs
-                    inputs.append(tags.input(value=value, name=field.dom_id(form), type="hidden"))
-            else:
-                options.append(tags.option(label, value=value))
-        if 'size' not in attrs:
-            attrs['size'] = 5
-        if 'id' in attrs :
-            attrs.pop('id')
-        return tags.select(name=name, multiple=self._multiple, id=name,
-                           options=options, **attrs) + '\n'.join(inputs)
-
-
-    def _render(self, form, field, renderer):
-        domid = field.dom_id(form)
-        jsnodes = {'widgetid': domid, 'from': 'from_' + domid, 'to': 'to_' + domid}
-        form._cw.add_onload(u'$(cw.jqNode("%s")).cwinoutwidget("%s", "%s");'
-                            % (jsnodes['widgetid'], jsnodes['from'], jsnodes['to']))
-        field.required=True
-        return self.template % {'widgetid': jsnodes['widgetid'],
-                                'inoutinput' : self.render_select(form, field, jsnodes['from']), # helpinfo select tag
-                                'resinput' : self.render_select(form, field, jsnodes['to'], selected=True), # select tag with resultats
-                                'addinput' : self.add_button % jsnodes,
-                                'removeinput': self.remove_button % jsnodes
-                                }
--- a/web/views/dotgraphview.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/views/dotgraphview.py	Fri Feb 10 16:53:52 2012 +0100
@@ -71,7 +71,7 @@
 
     def node_properties(self, entity):
         """return default DOT drawing options for a state or transition"""
-        return {'label': entity.dc_title(),
+        return {'label': entity.dc_long_title(),
                 'href': entity.absolute_url(),
                 'fontname': 'Courier', 'fontsize': 10, 'shape':'box',
                  }
--- a/web/views/primary.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/views/primary.py	Fri Feb 10 16:53:52 2012 +0100
@@ -82,9 +82,6 @@
         Renders the relation label next to the relation value if set to `True`.
         Otherwise, does only display the relation value.
 
-    :attr:`skip_none`
-        Does not render an attribute value that is None if set to `True`.
-
     :attr:`main_related_section`
         Renders the relations of the entity if set to `True`.
 
@@ -99,7 +96,6 @@
     title = _('primary')
     show_attr_label = True
     show_rel_label = True
-    skip_none = True
     rsection = uicfg.primaryview_section
     display_ctrl = uicfg.primaryview_display_ctrl
     main_related_section = True
@@ -194,9 +190,7 @@
         return u''
 
     def render_entity_attributes(self, entity):
-        """Renders all attributes and relations in the 'attributes' section. The
-        :attr:`skip_none` attribute controls the display of `None` valued
-        attributes.
+        """Renders all attributes and relations in the 'attributes' section. 
         """
         display_attributes = []
         for rschema, _, role, dispctrl in self._section_def(entity, 'attributes'):
@@ -210,7 +204,7 @@
                     value = self._cw.view(vid, rset)
                 else:
                     value = None
-            if not self.skip_none or (value is not None and value != ''):
+            if value is not None and value != '':
                 display_attributes.append( (rschema, role, dispctrl, value) )
         if display_attributes:
             self.w(u'<table>')
@@ -419,7 +413,7 @@
     __regid__ = 'attribute'
     __select__ = EntityView.__select__ & match_kwargs('rtype')
 
-    def entity_call(self, entity, rtype, role, **kwargs):
+    def entity_call(self, entity, rtype, role='subject', **kwargs):
         if self._cw.vreg.schema.rschema(rtype).final:
             self.w(entity.printable_value(rtype))
         else:
--- a/web/views/schema.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/views/schema.py	Fri Feb 10 16:53:52 2012 +0100
@@ -205,11 +205,11 @@
         _ = self._cw._
         # inheritance
         if entity.specializes:
-            self.w(u'<div>%s' % _('Parent class:'))
+            self.w(u'<div><strong>%s</strong>' % _('Parent class:'))
             self.wview('csv', entity.related('specializes', 'subject'))
             self.w(u'</div>')
         if entity.reverse_specializes:
-            self.w(u'<div>%s' % _('Sub-classes:'))
+            self.w(u'<div><strong>%s</strong>' % _('Sub-classes:'))
             self.wview('csv', entity.related('specializes', 'object'))
             self.w(u'</div>')
         # entity schema image
@@ -566,8 +566,14 @@
 
     def edge_properties(self, rschema, subjnode, objnode):
         """return default DOT drawing options for a relation schema"""
+        # Inheritance relation (i.e 'specializes').
+        if rschema is None:
+            kwargs = {'label': 'Parent class',
+                      'color' : 'grey',  'style' : 'filled',
+                      'arrowhead': 'empty',
+                      'fontsize': '10px'}
         # symmetric rels are handled differently, let yams decide what's best
-        if rschema.symmetric:
+        elif rschema.symmetric:
             kwargs = {'label': rschema.type,
                       'color': '#887788', 'style': 'dashed',
                       'dir': 'both', 'arrowhead': 'normal', 'arrowtail': 'normal',
--- a/web/views/tabs.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/views/tabs.py	Fri Feb 10 16:53:52 2012 +0100
@@ -61,11 +61,11 @@
             tabid, xml_escape(self._cw.build_url('json', **urlparams))))
         if show_spinbox:
             # Don't use ``alt`` since image is a *visual* helper for ajax
-            w(u'<img src="%s" alt="" id="%s-hole"/>'
+            w(u'<img style="display: none" src="%s" alt="" id="%s-hole"/>'
               % (xml_escape(self._cw.data_url('loading.gif')), tabid))
         else:
             w(u'<div id="%s-hole"></div>' % tabid)
-        w(u'<noscript><p>%s <a class="style: hidden" id="seo-%s" href="%s">%s</a></p></noscript>'
+        w(u'<noscript><p>%s <a id="seo-%s" href="%s">%s</a></p></noscript>'
           % (xml_escape(self._cw._('Link:')),
              tabid,
              xml_escape(self._cw.build_url(**urlparams)),
--- a/web/views/workflow.py	Fri Feb 10 16:31:39 2012 +0100
+++ b/web/views/workflow.py	Fri Feb 10 16:53:52 2012 +0100
@@ -398,10 +398,6 @@
                 props['fillcolor'] = '#88CC88'
         else:
             props['shape'] = 'ellipse'
-            descr = []
-            tr = stateortransition
-            if descr:
-                props['label'] += escape('\n'.join(descr))
         return props