some fixes so that deprecation warning are properly localized
"""Some views used to help to the edition process:organization: Logilab:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""__docformat__="restructuredtext en"_=unicodefromsimplejsonimportdumpsfromlogilab.common.decoratorsimportcachedfromlogilab.mtconverterimportxml_escapefromcubicwebimporttyped_eid,uilibfromcubicweb.schemaimportdisplay_namefromcubicweb.viewimportEntityViewfromcubicweb.selectorsimport(one_line_rset,non_final_entity,match_search_state,match_form_params)fromcubicweb.webimportformwidgetsasfw,formfieldsasfffromcubicweb.web.viewsimportbaseviews,linksearch_select_urldefrelation_id(eid,rtype,role,reid):"""return an identifier for a relation between two entities"""ifrole=='subject':returnu'%s:%s:%s'%(eid,rtype,reid)returnu'%s:%s:%s'%(reid,rtype,eid)deftoggleable_relation_link(eid,nodeid,label='x'):"""return javascript snippet to delete/undelete a relation between two entities """js=u"javascript: togglePendingDelete('%s', %s);"%(nodeid,xml_escape(dumps(eid)))returnu'[<a class="handle" href="%s" id="handle%s">%s</a>]'%(js,nodeid,label)classSearchForAssociationView(EntityView):"""view called by the edition view when the user asks to search for something to link to the edited eid """__regid__='search-associate'__select__=(one_line_rset()&match_search_state('linksearch')&non_final_entity())title=_('search for association')defcell_call(self,row,col):rset,vid,divid,paginate=self.filter_box_context_info()self.cw_rset=rsetself.w(u'<div id="%s">'%divid)self.paginate()self.wview(vid,rset,'noresult')self.w(u'</div>')@cacheddeffilter_box_context_info(self):entity=self.cw_rset.get_entity(0,0)role,eid,rtype,etype=self._cw.search_state[1]assertentity.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 contextrql,args=entity.unrelated_rql(rtype,etype,role,ordermethod='fetch_order',vocabconstraints=False)rset=self._cw.execute(rql,args,tuple(args))returnrset,'list',"search-associate-content",TrueclassOutOfContextSearch(EntityView):__regid__='outofcontext-search'defcell_call(self,row,col):entity=self.cw_rset.get_entity(row,col)erset=entity.as_rset()ifself._cw.match_search_state(erset):self.w(u'<a href="%s" title="%s">%s</a> <a href="%s" title="%s">[...]</a>'%(xml_escape(linksearch_select_url(self._cw,erset)),self._cw._('select this entity'),xml_escape(entity.view('textoutofcontext')),xml_escape(entity.absolute_url(vid='primary')),self._cw._('view detail for this entity')))else:entity.view('outofcontext',w=self.w)defget_pending_inserts(req,eid=None):"""shortcut to access req's pending_insert entry This is where are stored relations being added while editing an entity. This used to be stored in a temporary cookie. """pending=req.get_session_data('pending_insert')or()return['%s:%s:%s'%(subj,rel,obj)forsubj,rel,objinpendingifeidisNoneoreidin(subj,obj)]defget_pending_deletes(req,eid=None):"""shortcut to access req's pending_delete entry This is where are stored relations being removed while editing an entity. This used to be stored in a temporary cookie. """pending=req.get_session_data('pending_delete')or()return['%s:%s:%s'%(subj,rel,obj)forsubj,rel,objinpendingifeidisNoneoreidin(subj,obj)]defparse_relations_descr(rdescr):"""parse a string describing some relations, in the form subjeids:rtype:objeids where subjeids and objeids are eids separeted by a underscore return an iterator on (subject eid, relation type, object eid) found """forrstrinrdescr:subjs,rtype,objs=rstr.split(':')forsubjinsubjs.split('_'):forobjinobjs.split('_'):yieldtyped_eid(subj),rtype,typed_eid(obj)defdelete_relations(req,rdefs):"""delete relations from the repository"""# FIXME convert to using the syntax subject:relation:eidsexecute=req.executeforsubj,rtype,objinparse_relations_descr(rdefs):rql='DELETE X %s Y where X eid %%(x)s, Y eid %%(y)s'%rtypeexecute(rql,{'x':subj,'y':obj},('x','y'))req.set_message(req._('relations deleted'))definsert_relations(req,rdefs):"""insert relations into the repository"""execute=req.executeforsubj,rtype,objinparse_relations_descr(rdefs):rql='SET X %s Y where X eid %%(x)s, Y eid %%(y)s'%rtypeexecute(rql,{'x':subj,'y':obj},('x','y'))classGenericRelationsWidget(fw.FieldWidget):defrender(self,form,field,renderer):stream=[]w=stream.appendreq=form._cw_=req.___=_label=u'%s :'%__('This %s'%form.edited_entity.e_schema).capitalize()eid=form.edited_entity.eidw(u'<fieldset class="subentity">')w(u'<legend class="iformTitle">%s</legend>'%label)w(u'<table id="relatedEntities">')forrschema,role,relatedinfield.relations_table(form):# already linked entitiesifrelated:w(u'<tr><th class="labelCol">%s</th>'%rschema.display_name(req,role))w(u'<td>')w(u'<ul>')forviewparamsinrelated:w(u'<li class="invisible">%s<div id="span%s" class="%s">%s</div></li>'%(viewparams[1],viewparams[0],viewparams[2],viewparams[3]))ifnotform.force_displayandform.maxrelitems<len(related):link=(u'<span class="invisible">''[<a href="javascript: window.location.href+=\'&__force_display=1\'">%s</a>]''</span>'%_('view all'))w(u'<li class="invisible">%s</li>'%link)w(u'</ul>')w(u'</td>')w(u'</tr>')pendings=list(field.restore_pending_inserts(form))ifnotpendings:w(u'<tr><th> </th><td> </td></tr>')else:forrowinpendings:# soon to be linked to entitiesw(u'<tr id="tr%s">'%row[1])w(u'<th>%s</th>'%row[3])w(u'<td>')w(u'<a class="handle" title="%s" href="%s">[x]</a>'%(_('cancel this insert'),row[2]))w(u'<a id="a%s" class="editionPending" href="%s">%s</a>'%(row[1],row[4],xml_escape(row[5])))w(u'</td>')w(u'</tr>')w(u'<tr id="relationSelectorRow_%s" class="separator">'%eid)w(u'<th class="labelCol">')w(u'<select id="relationSelector_%s" tabindex="%s" ''onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'%(eid,req.next_tabindex(),xml_escape(dumps(eid))))w(u'<option value="">%s</option>'%_('select a relation'))fori18nrtype,rschema,roleinfield.relations:# more entities to link tow(u'<option value="%s_%s">%s</option>'%(rschema,role,i18nrtype))w(u'</select>')w(u'</th>')w(u'<td id="unrelatedDivs_%s"></td>'%eid)w(u'</tr>')w(u'</table>')w(u'</fieldset>')return'\n'.join(stream)classGenericRelationsField(ff.Field):widget=GenericRelationsWidgetdef__init__(self,relations,name='_cw_generic_field',**kwargs):assertrelationskwargs['eidparam']=Truesuper(GenericRelationsField,self).__init__(name,**kwargs)self.relations=relationsself.label=Nonedefprocess_posted(self,form):todelete=get_pending_deletes(form._cw)iftodelete:delete_relations(form._cw,todelete)toinsert=get_pending_inserts(form._cw)iftoinsert:insert_relations(form._cw,toinsert)return()defrelations_table(self,form):"""yiels 3-tuples (rtype, role, related_list) where <related_list> itself a list of : - node_id (will be the entity element's DOM id) - appropriate javascript's togglePendingDelete() function call - status 'pendingdelete' or '' - oneline view of related entity """entity=form.edited_entitypending_deletes=get_pending_deletes(form._cw,entity.eid)forlabel,rschema,roleinself.relations:related=[]ifentity.has_eid():rset=entity.related(rschema,role,limit=form.related_limit)ifrschema.has_perm(form._cw,'delete'):toggleable_rel_link_func=toggleable_relation_linkelse:toggleable_rel_link_func=lambdax,y,z:u''forrowinxrange(rset.rowcount):nodeid=relation_id(entity.eid,rschema,role,rset[row][0])ifnodeidinpending_deletes:status,label=u'pendingDelete','+'else:status,label=u'','x'dellink=toggleable_rel_link_func(entity.eid,nodeid,label)eview=form._cw.view('oneline',rset,row=row)related.append((nodeid,dellink,status,eview))yield(rschema,role,related)defrestore_pending_inserts(self,form):"""used to restore edition page as it was before clicking on 'search for <some entity type>' """entity=form.edited_entitypending_inserts=set(get_pending_inserts(form._cw,form.edited_entity.eid))forpendingidinpending_inserts:eidfrom,rtype,eidto=pendingid.split(':')iftyped_eid(eidfrom)==entity.eid:# subjectlabel=display_name(form._cw,rtype,'subject',entity.__regid__)reid=eidtoelse:label=display_name(form._cw,rtype,'object',entity.__regid__)reid=eidfromjscall="javascript: cancelPendingInsert('%s', 'tr', null, %s);" \%(pendingid,entity.eid)rset=form._cw.eid_rset(reid)eview=form._cw.view('text',rset,row=0)# XXX find a clean way to handle basketsifrset.description[0][0]=='Basket':eview='%s (%s)'%(eview,display_name(form._cw,'Basket'))yieldrtype,pendingid,jscall,label,reid,eviewclassUnrelatedDivs(EntityView):__regid__='unrelateddivs'__select__=match_form_params('relation')defcell_call(self,row,col):entity=self.cw_rset.get_entity(row,col)relname,role=self._cw.form.get('relation').rsplit('_',1)rschema=self._cw.vreg.schema.rschema(relname)hidden='hidden'inself._cw.formis_cell='is_cell'inself._cw.formself.w(self.build_unrelated_select_div(entity,rschema,role,is_cell=is_cell,hidden=hidden))defbuild_unrelated_select_div(self,entity,rschema,role,is_cell=False,hidden=True):options=[]divid='div%s_%s_%s'%(rschema.type,role,entity.eid)selectid='select%s_%s_%s'%(rschema.type,role,entity.eid)ifrschema.symetricorrole=='subject':targettypes=rschema.objects(entity.e_schema)etypes='/'.join(sorted(etype.display_name(self._cw)foretypeintargettypes))else:targettypes=rschema.subjects(entity.e_schema)etypes='/'.join(sorted(etype.display_name(self._cw)foretypeintargettypes))etypes=uilib.cut(etypes,self._cw.property_value('navigation.short-line-size'))options.append('<option>%s%s</option>'%(self._cw._('select a'),etypes))options+=self._get_select_options(entity,rschema,role)options+=self._get_search_options(entity,rschema,role,targettypes)if'Basket'inself._cw.vreg.schema:# XXXoptions+=self._get_basket_options(entity,rschema,role,targettypes)relname,role=self._cw.form.get('relation').rsplit('_',1)returnu"""\<div class="%s" id="%s"> <select id="%s" onchange="javascript: addPendingInsert(this.options[this.selectedIndex], %s, %s, '%s');">%s </select></div>"""%(hiddenand'hidden'or'',divid,selectid,xml_escape(dumps(entity.eid)),is_celland'true'or'null',relname,'\n'.join(options))def_get_select_options(self,entity,rschema,role):"""add options to search among all entities of each possible type"""options=[]pending_inserts=get_pending_inserts(self._cw,entity.eid)rtype=rschema.typeform=self._cw.vreg['forms'].select('edition',self._cw,entity=entity)field=form.field_by_name(rschema,role,entity.e_schema)limit=self._cw.property_value('navigation.combobox-limit')foreview,reidinfield.choices(form,limit):# XXX expect 'limit' arg on choicesifreidisNone:ifeview:# skip blank valueoptions.append('<option class="separator">-- %s --</option>'%xml_escape(eview))else:optionid=relation_id(entity.eid,rtype,role,reid)ifoptionidnotinpending_inserts:# prefix option's id with letters to make valid XHTML wiseoptions.append('<option id="id%s" value="%s">%s</option>'%(optionid,reid,xml_escape(eview)))returnoptionsdef_get_search_options(self,entity,rschema,role,targettypes):"""add options to search among all entities of each possible type"""options=[]_=self._cw._foreschemaintargettypes:mode='%s:%s:%s:%s'%(role,entity.eid,rschema.type,eschema)url=self._cw.build_url(entity.rest_path(),vid='search-associate',__mode=mode)options.append((eschema.display_name(self._cw),'<option value="%s">%s%s</option>'%(xml_escape(url),_('Search for'),eschema.display_name(self._cw))))return[oforl,oinsorted(options)]def_get_basket_options(self,entity,rschema,role,targettypes):options=[]rtype=rschema.type_=self._cw._forbasketeid,basketnameinself._get_basket_links(self._cw.user.eid,role,targettypes):optionid=relation_id(entity.eid,rtype,role,basketeid)options.append('<option id="%s" value="%s">%s%s</option>'%(optionid,basketeid,_('link to each item in'),xml_escape(basketname)))returnoptionsdef_get_basket_links(self,ueid,role,targettypes):targettypes=set(targettypes)forbasketeid,basketname,elementsinself._get_basket_info(ueid):baskettypes=elements.column_types(0)# if every elements in the basket can be attached to the# edited entityifbaskettypes&targettypes:yieldbasketeid,basketnamedef_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._cw.execute(basketrql,{'x':ueid},'x')forresultinbasketresultset:basketitemsrql='Any X WHERE X in_basket B, B eid %(x)s'rset=self._cw.execute(basketitemsrql,{'x':result[0]},'x')basketref.append((result[0],result[1],rset))returnbasketrefclassComboboxView(EntityView):"""the view used in combobox (unrelated entities) THIS IS A TEXT VIEW. DO NOT HTML_ESCAPE """__regid__='combobox'title=Nonedefcell_call(self,row,col):"""the combo-box view for an entity: same as text out of context view by default """self.wview('textoutofcontext',self.cw_rset,row=row,col=col)classEditableFinalView(baseviews.FinalView):"""same as FinalView but enables inplace-edition when possible"""__regid__='editable-final'defcell_call(self,row,col,props=None):entity,rtype=self.cw_rset.related_entity(row,col)ifentityisnotNone:self.w(entity.view('reledit',rtype=rtype))else:super(EditableFinalView,self).cell_call(row,col,props)