diff -r cb8ccbef8fa5 -r a5e6acffde30 web/views/editviews.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/views/editviews.py Wed Feb 18 19:26:48 2009 +0100 @@ -0,0 +1,310 @@ +"""Some views used to help to the edition process + +:organization: Logilab +:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" +__docformat__ = "restructuredtext en" + +from simplejson import dumps + +from logilab.common.decorators import cached +from logilab.mtconverter import html_escape + +from cubicweb import typed_eid +from cubicweb.view import EntityView +from cubicweb.selectors import (one_line_rset, non_final_entity, + match_search_state, match_form_params) +from cubicweb.common.uilib import cut +from cubicweb.web.views import linksearch_select_url +from cubicweb.web.form import relation_id +from cubicweb.web.views.baseviews import FinalView + +_ = unicode + +class SearchForAssociationView(EntityView): + """view called by the edition view when the user asks to search for + something to link to the edited eid + """ + id = 'search-associate' + __select__ = (one_line_rset() & match_search_state('linksearch') + & non_final_entity()) + + title = _('search for association') + + def cell_call(self, row, col): + rset, vid, divid, paginate = self.filter_box_context_info() + self.w(u'
' % divid) + self.pagination(self.req, rset, w=self.w) + self.wview(vid, rset, 'noresult') + self.w(u'
') + + @cached + def filter_box_context_info(self): + entity = self.entity(0, 0) + role, eid, rtype, etype = self.req.search_state[1] + assert entity.eid == typed_eid(eid) + # the default behaviour is to fetch all unrelated entities and display + # them. Use fetch_order and not fetch_unrelated_order as sort method + # since the latter is mainly there to select relevant items in the combo + # box, it doesn't give interesting result in this context + rql = entity.unrelated_rql(rtype, etype, role, + ordermethod='fetch_order', + vocabconstraints=False) + rset = self.req.execute(rql, {'x' : entity.eid}, 'x') + return rset, 'list', "search-associate-content", True + + +class OutOfContextSearch(EntityView): + id = 'outofcontext-search' + def cell_call(self, row, col): + entity = self.entity(row, col) + erset = entity.as_rset() + if self.req.match_search_state(erset): + self.w(u'%s [...]' % ( + html_escape(linksearch_select_url(self.req, erset)), + self.req._('select this entity'), + html_escape(entity.view('textoutofcontext')), + html_escape(entity.absolute_url(vid='primary')), + self.req._('view detail for this entity'))) + else: + entity.view('outofcontext', w=self.w) + + +class UnrelatedDivs(EntityView): + id = 'unrelateddivs' + __select__ = match_form_params('relation') + + @property + def limit(self): + if self.req.form.get('__force_display'): + return None + return self.req.property_value('navigation.related-limit') + 1 + + def cell_call(self, row, col): + entity = self.entity(row, col) + relname, target = self.req.form.get('relation').rsplit('_', 1) + rschema = self.schema.rschema(relname) + hidden = 'hidden' in self.req.form + is_cell = 'is_cell' in self.req.form + self.w(self.build_unrelated_select_div(entity, rschema, target, + is_cell=is_cell, hidden=hidden)) + + def build_unrelated_select_div(self, entity, rschema, target, + is_cell=False, hidden=True): + options = [] + divid = 'div%s_%s_%s' % (rschema.type, target, entity.eid) + selectid = 'select%s_%s_%s' % (rschema.type, target, entity.eid) + if rschema.symetric or target == 'subject': + targettypes = rschema.objects(entity.e_schema) + etypes = '/'.join(sorted(etype.display_name(self.req) for etype in targettypes)) + else: + targettypes = rschema.subjects(entity.e_schema) + etypes = '/'.join(sorted(etype.display_name(self.req) for etype in targettypes)) + etypes = cut(etypes, self.req.property_value('navigation.short-line-size')) + options.append('' % (self.req._('select a'), etypes)) + options += self._get_select_options(entity, rschema, target) + options += self._get_search_options(entity, rschema, target, targettypes) + if 'Basket' in self.schema: # XXX + options += self._get_basket_options(entity, rschema, target, targettypes) + relname, target = self.req.form.get('relation').rsplit('_', 1) + return u"""\ +
+ +
+""" % (hidden and 'hidden' or '', divid, selectid, html_escape(dumps(entity.eid)), + is_cell and 'true' or 'null', relname, '\n'.join(options)) + + def _get_select_options(self, entity, rschema, target): + """add options to search among all entities of each possible type""" + options = [] + eid = entity.eid + pending_inserts = self.req.get_pending_inserts(eid) + rtype = rschema.type + for eview, reid in entity.vocabulary(rschema, target, self.limit): + if reid is None: + options.append('' % html_escape(eview)) + else: + optionid = relation_id(eid, rtype, target, reid) + if optionid not in pending_inserts: + # prefix option's id with letters to make valid XHTML wise + options.append('' % + (optionid, reid, html_escape(eview))) + return options + + def _get_search_options(self, entity, rschema, target, targettypes): + """add options to search among all entities of each possible type""" + options = [] + _ = self.req._ + for eschema in targettypes: + mode = '%s:%s:%s:%s' % (target, entity.eid, rschema.type, eschema) + url = self.build_url(entity.rest_path(), vid='search-associate', + __mode=mode) + options.append((eschema.display_name(self.req), + '' % ( + html_escape(url), _('Search for'), eschema.display_name(self.req)))) + return [o for l, o in sorted(options)] + + def _get_basket_options(self, entity, rschema, target, targettypes): + options = [] + rtype = rschema.type + _ = self.req._ + for basketeid, basketname in self._get_basket_links(self.req.user.eid, + target, targettypes): + optionid = relation_id(entity.eid, rtype, target, basketeid) + options.append('' % ( + optionid, basketeid, _('link to each item in'), html_escape(basketname))) + return options + + def _get_basket_links(self, ueid, target, targettypes): + targettypes = set(targettypes) + for basketeid, basketname, elements in self._get_basket_info(ueid): + baskettypes = elements.column_types(0) + # if every elements in the basket can be attached to the + # edited entity + if baskettypes & targettypes: + yield basketeid, basketname + + def _get_basket_info(self, ueid): + basketref = [] + basketrql = 'Any B,N WHERE B is Basket, B owned_by U, U eid %(x)s, B name N' + basketresultset = self.req.execute(basketrql, {'x': ueid}, 'x') + for result in basketresultset: + basketitemsrql = 'Any X WHERE X in_basket B, B eid %(x)s' + rset = self.req.execute(basketitemsrql, {'x': result[0]}, 'x') + basketref.append((result[0], result[1], rset)) + return basketref + + +class ComboboxView(EntityView): + """the view used in combobox (unrelated entities) + + THIS IS A TEXT VIEW. DO NOT HTML_ESCAPE + """ + id = 'combobox' + title = None + + def cell_call(self, row, col): + """the combo-box view for an entity: same as text out of context view + by default + """ + self.wview('textoutofcontext', self.rset, row=row, col=col) + + +# class EditRelationView(EntityView): +# """Note: This is work in progress + +# This view is part of the edition view refactoring. +# It is still too big and cluttered with strange logic, but it's a start + +# The main idea is to be able to call an edition view for a specific +# relation. For example : +# self.wview('editrelation', person_rset, rtype='firstname') +# self.wview('editrelation', person_rset, rtype='works_for') +# """ +# id = 'editrelation' + +# __select__ = match_form_params('rtype') + +# # TODO: inlineview, multiple edit, (widget view ?) +# def cell_call(self, row, col, rtype=None, role='subject', targettype=None, +# showlabel=True): +# self.req.add_js( ('cubicweb.ajax.js', 'cubicweb.edition.js') ) +# entity = self.entity(row, col) +# rtype = self.req.form.get('rtype', rtype) +# showlabel = self.req.form.get('showlabel', showlabel) +# assert rtype is not None, "rtype is mandatory for 'edirelation' view" +# targettype = self.req.form.get('targettype', targettype) +# role = self.req.form.get('role', role) +# category = entity.rtags.get_category(rtype, targettype, role) +# if category in ('primary', 'secondary') or self.schema.rschema(rtype).is_final(): +# if hasattr(entity, '%s_format' % rtype): +# formatwdg = entity.get_widget('%s_format' % rtype, role) +# self.w(formatwdg.edit_render(entity)) +# self.w(u'
') +# wdg = entity.get_widget(rtype, role) +# if showlabel: +# self.w(u'%s' % wdg.render_label(entity)) +# self.w(u'%s %s %s' % +# (wdg.render_error(entity), wdg.edit_render(entity), +# wdg.render_help(entity),)) +# else: +# self._render_generic_relation(entity, rtype, role) + +# def _render_generic_relation(self, entity, relname, role): +# text = self.req.__('add %s %s %s' % (entity.e_schema, relname, role)) +# # pending operations +# operations = self.req.get_pending_operations(entity, relname, role) +# if operations['insert'] or operations['delete'] or 'unfold' in self.req.form: +# self.w(u'

%s

' % text) +# self._render_generic_relation_form(operations, entity, relname, role) +# else: +# divid = "%s%sreledit" % (relname, role) +# url = ajax_replace_url(divid, rql_for_eid(entity.eid), 'editrelation', +# {'unfold' : 1, 'relname' : relname, 'role' : role}) +# self.w(u'%s' % (url, text)) +# self.w(u'
' % divid) + + +# def _build_opvalue(self, entity, relname, target, role): +# if role == 'subject': +# return '%s:%s:%s' % (entity.eid, relname, target) +# else: +# return '%s:%s:%s' % (target, relname, entity.eid) + + +# def _render_generic_relation_form(self, operations, entity, relname, role): +# rqlexec = self.req.execute +# for optype, targets in operations.items(): +# for target in targets: +# self._render_pending(optype, entity, relname, target, role) +# opvalue = self._build_opvalue(entity, relname, target, role) +# self.w(u'- ' +# % (opvalue, entity.eid)) +# rset = rqlexec('Any X WHERE X eid %(x)s', {'x': target}, 'x') +# self.wview('oneline', rset) +# # now, unrelated ones +# self._render_unrelated_selection(entity, relname, role) + +# def _render_pending(self, optype, entity, relname, target, role): +# opvalue = self._build_opvalue(entity, relname, target, role) +# self.w(u'' +# % (optype, opvalue)) +# if optype == 'insert': +# checktext = '-' +# else: +# checktext = '+' +# rset = self.req.execute('Any X WHERE X eid %(x)s', {'x': target}, 'x') +# self.w(u"""[%s""" +# % (optype.capitalize(), relname, target, role, +# self.view('oneline', rset))) + +# def _render_unrelated_selection(self, entity, relname, role): +# rschema = self.schema.rschema(relname) +# if role == 'subject': +# targettypes = rschema.objects(entity.e_schema) +# else: +# targettypes = rschema.subjects(entity.e_schema) +# self.w(u'