web/views/autoform.py
changeset 3524 a3431f4e2f40
parent 3505 c0c7a944c00d
parent 3521 ad041dae15aa
child 3589 a5432f99f2d9
equal deleted inserted replaced
3505:c0c7a944c00d 3524:a3431f4e2f40
     6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     6 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
     7 """
     7 """
     8 __docformat__ = "restructuredtext en"
     8 __docformat__ = "restructuredtext en"
     9 _ = unicode
     9 _ = unicode
    10 
    10 
    11 from logilab.common.decorators import iclassmethod
    11 from logilab.common.decorators import iclassmethod, cached
    12 
    12 
    13 from cubicweb import typed_eid
    13 from cubicweb import typed_eid
    14 from cubicweb.web import stdmsgs, uicfg
    14 from cubicweb.web import stdmsgs, uicfg
    15 from cubicweb.web import form, formwidgets as fwdgs
    15 from cubicweb.web import form, formwidgets as fwdgs
    16 from cubicweb.web.formfields import guess_field
    16 from cubicweb.web.formfields import guess_field
   110 
   110 
   111     @property
   111     @property
   112     def form_needs_multipart(self):
   112     def form_needs_multipart(self):
   113         """true if the form needs enctype=multipart/form-data"""
   113         """true if the form needs enctype=multipart/form-data"""
   114         return self._subform_needs_multipart()
   114         return self._subform_needs_multipart()
       
   115 
       
   116     def build_context(self, rendervalues=None):
       
   117         super(AutomaticEntityForm, self).build_context(rendervalues)
       
   118         for form in self.inlined_forms():
       
   119             form.build_context(rendervalues)
   115 
   120 
   116     def _subform_needs_multipart(self, _tested=None):
   121     def _subform_needs_multipart(self, _tested=None):
   117         if _tested is None:
   122         if _tested is None:
   118             _tested = set()
   123             _tested = set()
   119         if super(AutomaticEntityForm, self).form_needs_multipart:
   124         if super(AutomaticEntityForm, self).form_needs_multipart:
   258                 eview = '%s (%s)' % (eview, display_name(self._cw, 'Basket'))
   263                 eview = '%s (%s)' % (eview, display_name(self._cw, 'Basket'))
   259             yield rtype, pendingid, jscall, label, reid, eview
   264             yield rtype, pendingid, jscall, label, reid, eview
   260 
   265 
   261     # inlined forms support ####################################################
   266     # inlined forms support ####################################################
   262 
   267 
       
   268     @cached
       
   269     def inlined_form_views(self):
       
   270         """compute and return list of inlined form views (hosting the inlined form object)
       
   271         """
       
   272         formviews = []
       
   273         entity = self.edited_entity
       
   274         for rschema, ttypes, role in self.inlined_relations():
       
   275             # show inline forms only if there's one possible target type
       
   276             # for rschema
       
   277             if len(ttypes) != 1:
       
   278                 self.warning('entity related by the %s relation should have '
       
   279                              'inlined form but there is multiple target types, '
       
   280                              'dunno what to do', rschema)
       
   281                 continue
       
   282             ttype = ttypes[0].type
       
   283             if self.should_inline_relation_form(rschema, ttype, role):
       
   284                 formviews += self.inline_edition_form_view(rschema, ttype, role)
       
   285                 if role == 'subject':
       
   286                     card = rschema.rproperty(entity.e_schema, ttype, 'cardinality')[0]
       
   287                 else:
       
   288                     card = rschema.rproperty(ttype, entity.e_schema, 'cardinality')[1]
       
   289                 # there is no related entity and we need at least one: we need to
       
   290                 # display one explicit inline-creation view
       
   291                 if self.should_display_inline_creation_form(rschema, formviews, card):
       
   292                     formviews += self.inline_creation_form_view(rschema, ttype, role)
       
   293                 # we can create more than one related entity, we thus display a link
       
   294                 # to add new related entities
       
   295                 if self.should_display_add_new_relation_link(rschema, formviews, card):
       
   296                     addnewlink = self.vreg['views'].select(
       
   297                         'inline-addnew-link', self.req,
       
   298                         etype=ttype, rtype=rschema, role=role,
       
   299                         peid=self.edited_entity.eid, pform=self, card=card)
       
   300                     formviews.append(addnewlink)
       
   301         return formviews
       
   302 
       
   303     def inlined_forms(self):
       
   304         for formview in self.inlined_form_views():
       
   305             if formview.form: # may be None for the addnew_link artefact form
       
   306                 yield formview.form
       
   307 
   263     def should_inline_relation_form(self, rschema, targettype, role):
   308     def should_inline_relation_form(self, rschema, targettype, role):
   264         """return true if the given relation with entity has role and a
   309         """return true if the given relation with entity has role and a
   265         targettype target should be inlined
   310         targettype target should be inlined
   266 
   311 
   267         At this point we now relation has inlined_attributes tag (eg is returned
   312         At this point we now relation has inlined_attributes tag (eg is returned
   268         by `inlined_relations()`. Overrides this for more finer control.
   313         by `inlined_relations()`. Overrides this for more finer control.
   269         """
   314         """
   270         return True
   315         return True
   271 
   316 
   272     def display_inline_edition_form(self, w, rschema, targettype, role,
   317     def should_display_inline_creation_form(self, rschema, existant, card):
   273                                      i18nctx):
   318         """return true if a creation form should be inlined
   274         """display inline forms for already related entities.
   319 
   275 
   320         by default true if there is no related entity and we need at least one
   276         Return True if some inlined form are actually displayed
   321         """
   277         """
   322         return not existant and card in '1+' or self._cw.form.has_key('force_%s_display' % rschema)
   278         existant = False
   323 
       
   324     def should_display_add_new_relation_link(self, rschema, existant, card):
       
   325         """return true if we should add a link to add a new creation form
       
   326         (through ajax call)
       
   327 
       
   328         by default true if there is no related entity or if the relation has
       
   329         multiple cardinality
       
   330         """
       
   331         return not existant or card in '+*'
       
   332 
       
   333     def should_hide_add_new_relation_link(self, rschema, card):
       
   334         """return true if once an inlined creation form is added, the 'add new'
       
   335         link should be hidden
       
   336 
       
   337         by default true if the relation has single cardinality
       
   338         """
       
   339         return card in '1?'
       
   340 
       
   341     def inline_edition_form_view(self, rschema, ttype, role):
       
   342         """yield inline form views for already related entities through the
       
   343         given relation
       
   344         """
   279         entity = self.edited_entity
   345         entity = self.edited_entity
   280         related = entity.has_eid() and entity.related(rschema, role)
   346         related = entity.has_eid() and entity.related(rschema, role)
   281         if related:
   347         if related:
       
   348             vvreg = self._cw.vreg['views']
   282             # display inline-edition view for all existing related entities
   349             # display inline-edition view for all existing related entities
   283             for i, relentity in enumerate(related.entities()):
   350             for i, relentity in enumerate(related.entities()):
   284                 if relentity.has_perm('update'):
   351                 if relentity.has_perm('update'):
   285                     w(self._cw.view('inline-edition', related, row=i, col=0,
   352                     yield vvreg.select('inline-edition', self._cw, related,
   286                                     rtype=rschema, role=role, ptype=entity.e_schema,
   353                                        row=i, col=0, rtype=rschema, role=role,
   287                                     peid=entity.eid, i18nctx=i18nctx))
   354                                        peid=entity.eid, pform=self)
   288                     existant = True
   355 
   289         return existant
   356     def inline_creation_form_view(self, rschema, ttype, role):
   290 
   357         """yield inline form views to a newly related (hence created) entity
   291     def should_display_inline_creation_form(self, rschema, existant, card):
   358         through the given relation
   292         """return true if a creation form should be inlined
   359         """
   293 
   360         yield self._cw.vreg['views'].select('inline-creation', self._cw,
   294         by default true if there is no related entity and we need at least one
   361                                             etype=ttype, rtype=rschema, role=role,
   295         """
   362                                             peid=self.edited_entity.eid, pform=self)
   296         return not existant and card in '1+' or self._cw.form.has_key('force_%s_display' % rschema)
       
   297 
       
   298     def display_inline_creation_form(self, w, rschema, targettype, role,
       
   299                                      i18nctx):
       
   300         """display inline forms to a newly related (hence created) entity.
       
   301 
       
   302         Return True if some inlined form are actually displayed
       
   303         """
       
   304         entity = self.edited_entity
       
   305         w(self._cw.view('inline-creation', None, etype=targettype,
       
   306                         peid=entity.eid, ptype=entity.e_schema,
       
   307                         rtype=rschema, role=role, i18nctx=i18nctx))
       
   308 
       
   309     def should_display_add_new_relation_link(self, rschema, existant, card):
       
   310         """return true if we should add a link to add a new creation form
       
   311         (through ajax call)
       
   312 
       
   313         by default true if there is no related entity or if the relation has
       
   314         multiple cardinality
       
   315         """
       
   316         return not existant or card in '+*'
       
   317 
       
   318     def should_hide_add_new_relation_link(self, rschema, card):
       
   319         """return true if once an inlined creation form is added, the 'add new'
       
   320         link should be hidden
       
   321 
       
   322         by default true if the relation has single cardinality
       
   323         """
       
   324         return card in '1?'
       
   325 
   363 
   326 
   364 
   327 def etype_relation_field(etype, rtype, role='subject'):
   365 def etype_relation_field(etype, rtype, role='subject'):
   328     eschema = AutomaticEntityForm.schema.eschema(etype)
   366     eschema = AutomaticEntityForm.schema.eschema(etype)
   329     return AutomaticEntityForm.field_by_name(rtype, role, eschema)
   367     return AutomaticEntityForm.field_by_name(rtype, role, eschema)
   335 uicfg.autoform_section.tag_attribute(('*', 'eid'), 'primary')
   373 uicfg.autoform_section.tag_attribute(('*', 'eid'), 'primary')
   336 uicfg.autoform_section.tag_attribute(('*', 'description'), 'secondary')
   374 uicfg.autoform_section.tag_attribute(('*', 'description'), 'secondary')
   337 uicfg.autoform_section.tag_attribute(('*', 'creation_date'), 'metadata')
   375 uicfg.autoform_section.tag_attribute(('*', 'creation_date'), 'metadata')
   338 uicfg.autoform_section.tag_attribute(('*', 'modification_date'), 'metadata')
   376 uicfg.autoform_section.tag_attribute(('*', 'modification_date'), 'metadata')
   339 uicfg.autoform_section.tag_attribute(('*', 'cwuri'), 'metadata')
   377 uicfg.autoform_section.tag_attribute(('*', 'cwuri'), 'metadata')
   340 uicfg.autoform_section.tag_subject_of(('*', 'in_state', '*'), 'primary')
   378 uicfg.autoform_section.tag_attribute(('*', 'has_text'), 'generated')
       
   379 uicfg.autoform_section.tag_subject_of(('*', 'in_state', '*'), 'generated')
   341 uicfg.autoform_section.tag_subject_of(('*', 'owned_by', '*'), 'metadata')
   380 uicfg.autoform_section.tag_subject_of(('*', 'owned_by', '*'), 'metadata')
   342 uicfg.autoform_section.tag_subject_of(('*', 'created_by', '*'), 'metadata')
   381 uicfg.autoform_section.tag_subject_of(('*', 'created_by', '*'), 'metadata')
   343 uicfg.autoform_section.tag_subject_of(('*', 'require_permission', '*'), 'generated')
   382 uicfg.autoform_section.tag_subject_of(('*', 'require_permission', '*'), 'generated')
   344 uicfg.autoform_section.tag_subject_of(('*', 'by_transition', '*'), 'primary')
   383 uicfg.autoform_section.tag_subject_of(('*', 'by_transition', '*'), 'primary')
   345 uicfg.autoform_section.tag_object_of(('*', 'by_transition', '*'), 'generated')
   384 uicfg.autoform_section.tag_object_of(('*', 'by_transition', '*'), 'generated')