web/views/editforms.py
branchtls-sprint
changeset 1423 39320a58faac
parent 1396 daaebf6b9922
child 1435 6cd6172718bb
equal deleted inserted replaced
1422:51b3fd55784e 1423:39320a58faac
    33 def relation_id(eid, rtype, role, reid):
    33 def relation_id(eid, rtype, role, reid):
    34     """return an identifier for a relation between two entities"""
    34     """return an identifier for a relation between two entities"""
    35     if role == 'subject':
    35     if role == 'subject':
    36         return u'%s:%s:%s' % (eid, rtype, reid)
    36         return u'%s:%s:%s' % (eid, rtype, reid)
    37     return u'%s:%s:%s' % (reid, rtype, eid)
    37     return u'%s:%s:%s' % (reid, rtype, eid)
    38         
    38 
    39 def toggable_relation_link(eid, nodeid, label='x'):
    39 def toggable_relation_link(eid, nodeid, label='x'):
    40     """return javascript snippet to delete/undelete a relation between two
    40     """return javascript snippet to delete/undelete a relation between two
    41     entities
    41     entities
    42     """
    42     """
    43     js = u"javascript: togglePendingDelete('%s', %s);" % (
    43     js = u"javascript: togglePendingDelete('%s', %s);" % (
    51     id = 'deleteconf'
    51     id = 'deleteconf'
    52     title = _('delete')
    52     title = _('delete')
    53     # don't use navigation, all entities asked to be deleted should be displayed
    53     # don't use navigation, all entities asked to be deleted should be displayed
    54     # else we will only delete the displayed page
    54     # else we will only delete the displayed page
    55     need_navigation = False
    55     need_navigation = False
    56     
    56 
    57     def call(self):
    57     def call(self):
    58         """ask for confirmation before real deletion"""
    58         """ask for confirmation before real deletion"""
    59         req, w = self.req, self.w
    59         req, w = self.req, self.w
    60         _ = req._
    60         _ = req._
    61         w(u'<script type="text/javascript">updateMessage(\'%s\');</script>\n'
    61         w(u'<script type="text/javascript">updateMessage(\'%s\');</script>\n'
    81         w(form.form_render())
    81         w(form.form_render())
    82 
    82 
    83 
    83 
    84 class ClickAndEditFormView(FormViewMixIn, EntityView):
    84 class ClickAndEditFormView(FormViewMixIn, EntityView):
    85     """form used to permit ajax edition of an attribute of an entity in a view
    85     """form used to permit ajax edition of an attribute of an entity in a view
    86     
    86 
    87     (double-click on the field to see an appropriate edition widget)
    87     (double-click on the field to see an appropriate edition widget)
    88     """
    88     """
    89     id = 'reledit'
    89     id = 'reledit'
    90     __select__ = non_final_entity() & match_kwargs('rtype')
    90     __select__ = non_final_entity() & match_kwargs('rtype')
    91     
    91 
    92     # FIXME editableField class could be toggleable from userprefs
    92     # FIXME editableField class could be toggleable from userprefs
    93     
    93 
    94     onsubmit = ("return inlineValidateForm('%(divid)s-form', '%(rtype)s', "
    94     onsubmit = ("return inlineValidateForm('%(divid)s-form', '%(rtype)s', "
    95                 "'%(eid)s', '%(divid)s', %(reload)s);")
    95                 "'%(eid)s', '%(divid)s', %(reload)s);")
    96     ondblclick = "showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')"
    96     ondblclick = "showInlineEditionForm(%(eid)s, '%(rtype)s', '%(divid)s')"
    97     
    97 
    98     def cell_call(self, row, col, rtype=None, role='subject', reload=False):
    98     def cell_call(self, row, col, rtype=None, role='subject', reload=False):
    99         """display field to edit entity's `rtype` relation on double-click"""
    99         """display field to edit entity's `rtype` relation on double-click"""
   100         entity = self.entity(row, col)
   100         entity = self.entity(row, col)
   101         if getattr(entity, rtype) is None:
   101         if getattr(entity, rtype) is None:
   102             value = self.req._('not specified')
   102             value = self.req._('not specified')
   140     cwtarget = 'eformframe'
   140     cwtarget = 'eformframe'
   141     cssclass = 'entityForm'
   141     cssclass = 'entityForm'
   142     copy_nav_params = True
   142     copy_nav_params = True
   143     form_buttons = [SubmitButton(stdmsgs.BUTTON_OK),
   143     form_buttons = [SubmitButton(stdmsgs.BUTTON_OK),
   144                     Button(stdmsgs.BUTTON_APPLY, cwaction='apply'),
   144                     Button(stdmsgs.BUTTON_APPLY, cwaction='apply'),
   145                     Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]    
   145                     Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
   146     attrcategories = ('primary', 'secondary')
   146     attrcategories = ('primary', 'secondary')
   147     # class attributes below are actually stored in the uicfg module since we
   147     # class attributes below are actually stored in the uicfg module since we
   148     # don't want them to be reloaded
   148     # don't want them to be reloaded
   149     rcategories = uicfg.rcategories
   149     rcategories = uicfg.rcategories
   150     rfields = uicfg.rfields
   150     rfields = uicfg.rfields
   151     rwidgets = uicfg.rwidgets
   151     rwidgets = uicfg.rwidgets
   152     rinlined = uicfg.rinlined
   152     rinlined = uicfg.rinlined
   153     rpermissions_overrides = uicfg.rpermissions_overrides
   153     rpermissions_overrides = uicfg.rpermissions_overrides
   154         
   154 
   155     @classmethod
   155     @classmethod
   156     def vreg_initialization_completed(cls):
   156     def vreg_initialization_completed(cls):
   157         """set default category tags for relations where it's not yet defined in
   157         """set default category tags for relations where it's not yet defined in
   158         the category relation tags
   158         the category relation tags
   159         """
   159         """
   174                                 category = 'generated'
   174                                 category = 'generated'
   175                             else:
   175                             else:
   176                                 category = 'primary'
   176                                 category = 'primary'
   177                         elif rschema.is_final():
   177                         elif rschema.is_final():
   178                             category = 'secondary'
   178                             category = 'secondary'
   179                         else: 
   179                         else:
   180                             category = 'generic'
   180                             category = 'generic'
   181                         cls.rcategories.set_rtag(category, rschema, role, X, Y)
   181                         cls.rcategories.set_rtag(category, rschema, role, X, Y)
   182 
   182 
   183     @classmethod
   183     @classmethod
   184     def erelations_by_category(cls, entity, categories=None, permission=None, rtags=None):
   184     def erelations_by_category(cls, entity, categories=None, permission=None, rtags=None):
   239                         and eid and entity.related(rschema.type, role)
   239                         and eid and entity.related(rschema.type, role)
   240                         and not rschema.has_perm(entity.req, 'delete', toeid=eid,
   240                         and not rschema.has_perm(entity.req, 'delete', toeid=eid,
   241                                                  fromeid=entity.related(rschema.type, role)[0][0])):
   241                                                  fromeid=entity.related(rschema.type, role)[0][0])):
   242                         continue
   242                         continue
   243             yield (rschema, targetschemas, role)
   243             yield (rschema, targetschemas, role)
   244     
   244 
   245     @classmethod
   245     @classmethod
   246     def esrelations_by_category(cls, entity, categories=None, permission=None):
   246     def esrelations_by_category(cls, entity, categories=None, permission=None):
   247         """filter out result of relations_by_category(categories, permission) by
   247         """filter out result of relations_by_category(categories, permission) by
   248         removing final relations
   248         removing final relations
   249 
   249 
   250         return a sorted list of (relation's label, relation'schema, role) 
   250         return a sorted list of (relation's label, relation'schema, role)
   251         """
   251         """
   252         result = []
   252         result = []
   253         for rschema, ttypes, role in cls.erelations_by_category(
   253         for rschema, ttypes, role in cls.erelations_by_category(
   254             entity, categories, permission):
   254             entity, categories, permission):
   255             if rschema.is_final():
   255             if rschema.is_final():
   256                 continue
   256                 continue
   257             result.append((rschema.display_name(entity.req, role), rschema, role))
   257             result.append((rschema.display_name(entity.req, role), rschema, role))
   258         return sorted(result)
   258         return sorted(result)
   259     
   259 
   260     @iclassmethod
   260     @iclassmethod
   261     def field_by_name(cls_or_self, name, role='subject', eclass=None):
   261     def field_by_name(cls_or_self, name, role='subject', eclass=None):
   262         """return field with the given name and role. If field is not explicitly
   262         """return field with the given name and role. If field is not explicitly
   263         defined for the form but `eclass` is specified, guess_field will be
   263         defined for the form but `eclass` is specified, guess_field will be
   264         called.
   264         called.
   271             field = guess_field(eclass, cls_or_self.schema.rschema(name), role,
   271             field = guess_field(eclass, cls_or_self.schema.rschema(name), role,
   272                                 eidparam=True)
   272                                 eidparam=True)
   273             if field is None:
   273             if field is None:
   274                 raise
   274                 raise
   275             return field
   275             return field
   276     
   276 
   277     def __init__(self, *args, **kwargs):
   277     def __init__(self, *args, **kwargs):
   278         super(AutomaticEntityForm, self).__init__(*args, **kwargs)
   278         super(AutomaticEntityForm, self).__init__(*args, **kwargs)
   279         if self.edited_entity.has_eid():
   279         if self.edited_entity.has_eid():
   280             self.edited_entity.complete()
   280             self.edited_entity.complete()
   281         for rschema, role in self.editable_attributes():
   281         for rschema, role in self.editable_attributes():
   300                                     eidparam=True)
   300                                     eidparam=True)
   301             if field is not None:
   301             if field is not None:
   302                 self.fields.append(field)
   302                 self.fields.append(field)
   303         self.maxrelitems = self.req.property_value('navigation.related-limit')
   303         self.maxrelitems = self.req.property_value('navigation.related-limit')
   304         self.force_display = bool(self.req.form.get('__force_display'))
   304         self.force_display = bool(self.req.form.get('__force_display'))
   305         
   305 
   306     @property
   306     @property
   307     def related_limit(self):
   307     def related_limit(self):
   308         if self.force_display:
   308         if self.force_display:
   309             return None
   309             return None
   310         return self.maxrelitems + 1
   310         return self.maxrelitems + 1
   311     
   311 
   312     def relations_by_category(self, categories=None, permission=None):
   312     def relations_by_category(self, categories=None, permission=None):
   313         """return a list of (relation schema, target schemas, role) matching
   313         """return a list of (relation schema, target schemas, role) matching
   314         given category(ies) and permission
   314         given category(ies) and permission
   315         """
   315         """
   316         return self.erelations_by_category(self.edited_entity, categories,
   316         return self.erelations_by_category(self.edited_entity, categories,
   317                                            permission)
   317                                            permission)
   318     
   318 
   319     def inlined_relations(self):
   319     def inlined_relations(self):
   320         """return a list of (relation schema, target schemas, role) matching
   320         """return a list of (relation schema, target schemas, role) matching
   321         given category(ies) and permission
   321         given category(ies) and permission
   322         """
   322         """
   323         # we'll need an initialized varmaker if there are some inlined relation
   323         # we'll need an initialized varmaker if there are some inlined relation
   324         self.initialize_varmaker()
   324         self.initialize_varmaker()
   325         return self.erelations_by_category(self.edited_entity, True, 'add', self.rinlined)
   325         return self.erelations_by_category(self.edited_entity, True, 'add', self.rinlined)
   326     
   326 
   327     def srelations_by_category(self, categories=None, permission=None):
   327     def srelations_by_category(self, categories=None, permission=None):
   328         """filter out result of relations_by_category(categories, permission) by
   328         """filter out result of relations_by_category(categories, permission) by
   329         removing final relations
   329         removing final relations
   330 
   330 
   331         return a sorted list of (relation's label, relation'schema, role) 
   331         return a sorted list of (relation's label, relation'schema, role)
   332         """
   332         """
   333         return self.esrelations_by_category(self.edited_entity, categories,
   333         return self.esrelations_by_category(self.edited_entity, categories,
   334                                            permission)
   334                                            permission)
   335         
   335 
   336     def action(self):
   336     def action(self):
   337         """return the form's action attribute. Default to validateform if not
   337         """return the form's action attribute. Default to validateform if not
   338         explicitly overriden.
   338         explicitly overriden.
   339         """
   339         """
   340         try:
   340         try:
   341             return self._action
   341             return self._action
   342         except AttributeError:
   342         except AttributeError:
   343             return self.build_url('validateform')
   343             return self.build_url('validateform')
   344         
   344 
   345     def set_action(self, value):
   345     def set_action(self, value):
   346         """override default action"""
   346         """override default action"""
   347         self._action = value
   347         self._action = value
   348         
   348 
   349     action = property(action, set_action)
   349     action = property(action, set_action)
   350     
   350 
   351     def editable_attributes(self):
   351     def editable_attributes(self):
   352         """return a list of (relation schema, role) to edit for the entity"""
   352         """return a list of (relation schema, role) to edit for the entity"""
   353         return [(rschema, x) for rschema, _, x in self.relations_by_category(
   353         return [(rschema, x) for rschema, _, x in self.relations_by_category(
   354             self.attrcategories, 'add') if rschema != 'eid']
   354             self.attrcategories, 'add') if rschema != 'eid']
   355         
   355 
   356     def relations_table(self):
   356     def relations_table(self):
   357         """yiels 3-tuples (rtype, target, related_list)
   357         """yiels 3-tuples (rtype, target, related_list)
   358         where <related_list> itself a list of :
   358         where <related_list> itself a list of :
   359           - node_id (will be the entity element's DOM id)
   359           - node_id (will be the entity element's DOM id)
   360           - appropriate javascript's togglePendingDelete() function call
   360           - appropriate javascript's togglePendingDelete() function call
   361           - status 'pendingdelete' or ''
   361           - status 'pendingdelete' or ''
   362           - oneline view of related entity
   362           - oneline view of related entity
   363         """
   363         """
   364         entity = self.edited_entity
   364         entity = self.edited_entity
   365         pending_deletes = self.req.get_pending_deletes(entity.eid)        
   365         pending_deletes = self.req.get_pending_deletes(entity.eid)
   366         for label, rschema, role in self.srelations_by_category('generic', 'add'):
   366         for label, rschema, role in self.srelations_by_category('generic', 'add'):
   367             relatedrset = entity.related(rschema, role, limit=self.related_limit)
   367             relatedrset = entity.related(rschema, role, limit=self.related_limit)
   368             if rschema.has_perm(self.req, 'delete'):
   368             if rschema.has_perm(self.req, 'delete'):
   369                 toggable_rel_link_func = toggable_relation_link
   369                 toggable_rel_link_func = toggable_relation_link
   370             else:
   370             else:
   381                     label = 'x'
   381                     label = 'x'
   382                 dellink = toggable_rel_link_func(entity.eid, nodeid, label)
   382                 dellink = toggable_rel_link_func(entity.eid, nodeid, label)
   383                 eview = self.view('oneline', relatedrset, row=row)
   383                 eview = self.view('oneline', relatedrset, row=row)
   384                 related.append((nodeid, dellink, status, eview))
   384                 related.append((nodeid, dellink, status, eview))
   385             yield (rschema, role, related)
   385             yield (rschema, role, related)
   386             
   386 
   387     def restore_pending_inserts(self, cell=False):
   387     def restore_pending_inserts(self, cell=False):
   388         """used to restore edition page as it was before clicking on
   388         """used to restore edition page as it was before clicking on
   389         'search for <some entity type>'
   389         'search for <some entity type>'
   390         """
   390         """
   391         eid = self.edited_entity.eid
   391         eid = self.edited_entity.eid
   405             eview = self.view('text', rset, row=0)
   405             eview = self.view('text', rset, row=0)
   406             # XXX find a clean way to handle baskets
   406             # XXX find a clean way to handle baskets
   407             if rset.description[0][0] == 'Basket':
   407             if rset.description[0][0] == 'Basket':
   408                 eview = '%s (%s)' % (eview, display_name(self.req, 'Basket'))
   408                 eview = '%s (%s)' % (eview, display_name(self.req, 'Basket'))
   409             yield rtype, pendingid, jscall, label, reid, eview
   409             yield rtype, pendingid, jscall, label, reid, eview
   410             
   410 
   411     # should_* method extracted to allow overriding
   411     # should_* method extracted to allow overriding
   412     
   412 
   413     def should_inline_relation_form(self, rschema, targettype, role):
   413     def should_inline_relation_form(self, rschema, targettype, role):
   414         """return true if the given relation with entity has role and a
   414         """return true if the given relation with entity has role and a
   415         targettype target should be inlined
   415         targettype target should be inlined
   416         """
   416         """
   417         return self.rinlined.etype_rtag(self.edited_entity.id, rschema, role, targettype)
   417         return self.rinlined.etype_rtag(self.edited_entity.id, rschema, role, targettype)
   430         by default true if there is no related entity or if the relation has
   430         by default true if there is no related entity or if the relation has
   431         multiple cardinality
   431         multiple cardinality
   432         """
   432         """
   433         return not existant or card in '+*'
   433         return not existant or card in '+*'
   434 
   434 
   435     
   435 
   436 class EditionFormView(FormViewMixIn, EntityView):
   436 class EditionFormView(FormViewMixIn, EntityView):
   437     """display primary entity edition form"""    
   437     """display primary entity edition form"""
   438     id = 'edition'
   438     id = 'edition'
   439     # add yes() so it takes precedence over deprecated views in baseforms,
   439     # add yes() so it takes precedence over deprecated views in baseforms,
   440     # though not baseforms based customized view
   440     # though not baseforms based customized view
   441     __select__ = one_line_rset() & non_final_entity() & yes()
   441     __select__ = one_line_rset() & non_final_entity() & yes()
   442 
   442 
   443     title = _('edition')
   443     title = _('edition')
   444     renderer = EntityFormRenderer()
   444     renderer = EntityFormRenderer()
   445     
   445 
   446     def cell_call(self, row, col, **kwargs):
   446     def cell_call(self, row, col, **kwargs):
   447         entity = self.complete_entity(row, col)
   447         entity = self.complete_entity(row, col)
   448         self.render_form(entity)
   448         self.render_form(entity)
   449         
   449 
   450     def render_form(self, entity):
   450     def render_form(self, entity):
   451         """fetch and render the form"""
   451         """fetch and render the form"""
   452         self.form_title(entity)
   452         self.form_title(entity)
   453         form = self.vreg.select_object('forms', 'edition', self.req, entity.rset,
   453         form = self.vreg.select_object('forms', 'edition', self.req, entity.rset,
   454                                        row=entity.row, col=entity.col, entity=entity,
   454                                        row=entity.row, col=entity.col, entity=entity,
   457         self.w(form.form_render(renderer=self.renderer, formvid=u'edition'))
   457         self.w(form.form_render(renderer=self.renderer, formvid=u'edition'))
   458 
   458 
   459     def init_form(self, form, entity):
   459     def init_form(self, form, entity):
   460         """customize your form before rendering here"""
   460         """customize your form before rendering here"""
   461         form.form_add_hidden(u'__maineid', entity.eid)
   461         form.form_add_hidden(u'__maineid', entity.eid)
   462         
   462 
   463     def form_title(self, entity):
   463     def form_title(self, entity):
   464         """the form view title"""
   464         """the form view title"""
   465         ptitle = self.req._(self.title)
   465         ptitle = self.req._(self.title)
   466         self.w(u'<div class="formTitle"><span>%s %s</span></div>' % (
   466         self.w(u'<div class="formTitle"><span>%s %s</span></div>' % (
   467             entity.dc_type(), ptitle and '(%s)' % ptitle))
   467             entity.dc_type(), ptitle and '(%s)' % ptitle))
   468     
   468 
   469     def submited_message(self):
   469     def submited_message(self):
   470         """return the message that will be displayed on successful edition"""
   470         """return the message that will be displayed on successful edition"""
   471         return self.req._('entity edited')
   471         return self.req._('entity edited')
   472 
   472 
   473         
   473 
   474 class CreationFormView(EditionFormView):
   474 class CreationFormView(EditionFormView):
   475     """display primary entity creation form"""    
   475     """display primary entity creation form"""
   476     id = 'creation'
   476     id = 'creation'
   477     __select__ = specified_etype_implements('Any') & yes()
   477     __select__ = specified_etype_implements('Any') & yes()
   478     
   478 
   479     title = _('creation')
   479     title = _('creation')
   480     
   480 
   481     def call(self, **kwargs):
   481     def call(self, **kwargs):
   482         """creation view for an entity"""
   482         """creation view for an entity"""
   483         etype = kwargs.pop('etype', self.req.form.get('etype'))
   483         etype = kwargs.pop('etype', self.req.form.get('etype'))
   484         try:
   484         try:
   485             entity = self.vreg.etype_class(etype)(self.req, None, None)
   485             entity = self.vreg.etype_class(etype)(self.req, None, None)
   487             self.w(self.req._('no such entity type %s') % etype)
   487             self.w(self.req._('no such entity type %s') % etype)
   488         else:
   488         else:
   489             self.initialize_varmaker()
   489             self.initialize_varmaker()
   490             entity.eid = self.varmaker.next()
   490             entity.eid = self.varmaker.next()
   491             self.render_form(entity)
   491             self.render_form(entity)
   492     
   492 
   493     def form_title(self, entity):
   493     def form_title(self, entity):
   494         """the form view title"""
   494         """the form view title"""
   495         if '__linkto' in self.req.form:
   495         if '__linkto' in self.req.form:
   496             if isinstance(self.req.form['__linkto'], list):
   496             if isinstance(self.req.form['__linkto'], list):
   497                 # XXX which one should be considered (case: add a ticket to a
   497                 # XXX which one should be considered (case: add a ticket to a
   509                     entity.e_schema, linkto_type, rtype, entity.e_schema))
   509                     entity.e_schema, linkto_type, rtype, entity.e_schema))
   510             msg = title % {'linkto' : self.view('incontext', linkto_rset)}
   510             msg = title % {'linkto' : self.view('incontext', linkto_rset)}
   511             self.w(u'<div class="formTitle notransform"><span>%s</span></div>' % msg)
   511             self.w(u'<div class="formTitle notransform"><span>%s</span></div>' % msg)
   512         else:
   512         else:
   513             super(CreationFormView, self).form_title(entity)
   513             super(CreationFormView, self).form_title(entity)
   514     
   514 
   515     def url(self):
   515     def url(self):
   516         """return the url associated with this view"""
   516         """return the url associated with this view"""
   517         return self.create_url(self.req.form.get('etype'))
   517         return self.create_url(self.req.form.get('etype'))
   518     
   518 
   519     def submited_message(self):
   519     def submited_message(self):
   520         """return the message that will be displayed on successful edition"""
   520         """return the message that will be displayed on successful edition"""
   521         return self.req._('entity created')
   521         return self.req._('entity created')
   522 
   522 
   523 
   523 
   524 class CopyFormView(EditionFormView):
   524 class CopyFormView(EditionFormView):
   525     """display primary entity creation form initialized with values from another
   525     """display primary entity creation form initialized with values from another
   526     entity
   526     entity
   527     """    
   527     """
   528     id = 'copy'
   528     id = 'copy'
   529     def render_form(self, entity):
   529     def render_form(self, entity):
   530         """fetch and render the form"""
   530         """fetch and render the form"""
   531         # make a copy of entity to avoid altering the entity in the
   531         # make a copy of entity to avoid altering the entity in the
   532         # request's cache. 
   532         # request's cache.
   533         self.newentity = copy(entity)
   533         self.newentity = copy(entity)
   534         self.copying = self.newentity.eid
   534         self.copying = self.newentity.eid
   535         self.newentity.eid = None
   535         self.newentity.eid = None
   536         self.w(u'<script type="text/javascript">updateMessage("%s");</script>\n'
   536         self.w(u'<script type="text/javascript">updateMessage("%s");</script>\n'
   537                % self.req._('Please note that this is only a shallow copy'))
   537                % self.req._('Please note that this is only a shallow copy'))
   538         super(CopyFormView, self).render_form(entity)
   538         super(CopyFormView, self).render_form(entity)
   539         del self.newentity
   539         del self.newentity
   540     
   540 
   541     def init_form(self, form, entity):
   541     def init_form(self, form, entity):
   542         """customize your form before rendering here"""
   542         """customize your form before rendering here"""
   543         super(CopyFormView, self).init_form(form, entity)
   543         super(CopyFormView, self).init_form(form, entity)
   544         if entity.eid == self.newentity.eid:
   544         if entity.eid == self.newentity.eid:
   545             form.form_add_hidden('__cloned_eid', self.copying, eidparam=True)
   545             form.form_add_hidden('__cloned_eid', self.copying, eidparam=True)
   546     
   546 
   547     def submited_message(self):
   547     def submited_message(self):
   548         """return the message that will be displayed on successful edition"""
   548         """return the message that will be displayed on successful edition"""
   549         return self.req._('entity copied')
   549         return self.req._('entity copied')
   550 
   550 
   551     
   551 
   552 class TableEditForm(CompositeForm):
   552 class TableEditForm(CompositeForm):
   553     id = 'muledit'
   553     id = 'muledit'
   554     onsubmit = "return validateForm('entityForm', null);"
   554     onsubmit = "return validateForm('entityForm', null);"
   555     form_buttons = [SubmitButton(_('validate modifications on selected items')),
   555     form_buttons = [SubmitButton(_('validate modifications on selected items')),
   556                     ResetButton(_('revert changes'))]
   556                     ResetButton(_('revert changes'))]
   557     
   557 
   558     def __init__(self, *args, **kwargs):
   558     def __init__(self, *args, **kwargs):
   559         super(TableEditForm, self).__init__(*args, **kwargs)
   559         super(TableEditForm, self).__init__(*args, **kwargs)
   560         for row in xrange(len(self.rset)):
   560         for row in xrange(len(self.rset)):
   561             form = self.vreg.select_object('forms', 'edition', self.req, self.rset,
   561             form = self.vreg.select_object('forms', 'edition', self.req, self.rset,
   562                                            row=row, attrcategories=('primary',),
   562                                            row=row, attrcategories=('primary',),
   563                                            set_error_url=False)
   563                                            set_error_url=False)
   564             # XXX rely on the EntityCompositeFormRenderer to put the eid input
   564             # XXX rely on the EntityCompositeFormRenderer to put the eid input
   565             form.remove_field(form.field_by_name('eid'))
   565             form.remove_field(form.field_by_name('eid'))
   566             self.form_add_subform(form)
   566             self.form_add_subform(form)
   567 
   567 
   568         
   568 
   569 class TableEditFormView(FormViewMixIn, EntityView):
   569 class TableEditFormView(FormViewMixIn, EntityView):
   570     id = 'muledit'
   570     id = 'muledit'
   571     __select__ = EntityView.__select__ & yes()
   571     __select__ = EntityView.__select__ & yes()
   572     title = _('multiple edit')
   572     title = _('multiple edit')
   573     
   573 
   574     def call(self, **kwargs):
   574     def call(self, **kwargs):
   575         """a view to edit multiple entities of the same type the first column
   575         """a view to edit multiple entities of the same type the first column
   576         should be the eid
   576         should be the eid
   577         """
   577         """
   578         #self.form_title(entity)
   578         #self.form_title(entity)
   582 
   582 
   583 class InlineEntityEditionFormView(FormViewMixIn, EntityView):
   583 class InlineEntityEditionFormView(FormViewMixIn, EntityView):
   584     id = 'inline-edition'
   584     id = 'inline-edition'
   585     __select__ = non_final_entity() & match_kwargs('peid', 'rtype')
   585     __select__ = non_final_entity() & match_kwargs('peid', 'rtype')
   586     removejs = "removeInlinedEntity('%s', '%s', '%s')"
   586     removejs = "removeInlinedEntity('%s', '%s', '%s')"
   587     
   587 
   588     def call(self, **kwargs):
   588     def call(self, **kwargs):
   589         """redefine default call() method to avoid automatic
   589         """redefine default call() method to avoid automatic
   590         insertions of <div class="section"> between each row of
   590         insertions of <div class="section"> between each row of
   591         the resultset
   591         the resultset
   592         """
   592         """
   602         """
   602         """
   603         entity = self.entity(row, col)
   603         entity = self.entity(row, col)
   604         divonclick = "restoreInlinedEntity('%s', '%s', '%s')" % (peid, rtype,
   604         divonclick = "restoreInlinedEntity('%s', '%s', '%s')" % (peid, rtype,
   605                                                                  entity.eid)
   605                                                                  entity.eid)
   606         self.render_form(entity, peid, rtype, role, divonclick=divonclick)
   606         self.render_form(entity, peid, rtype, role, divonclick=divonclick)
   607         
   607 
   608     def render_form(self, entity, peid, rtype, role, **kwargs):
   608     def render_form(self, entity, peid, rtype, role, **kwargs):
   609         """fetch and render the form"""
   609         """fetch and render the form"""
   610         form = self.vreg.select_object('forms', 'edition', self.req, None,
   610         form = self.vreg.select_object('forms', 'edition', self.req, None,
   611                                        entity=entity)
   611                                        entity=entity, set_error_url=False)
   612         self.add_hiddens(form, entity, peid, rtype, role)
   612         self.add_hiddens(form, entity, peid, rtype, role)
   613         divid = '%s-%s-%s' % (peid, rtype, entity.eid)
   613         divid = '%s-%s-%s' % (peid, rtype, entity.eid)
   614         title = self.schema.rschema(rtype).display_name(self.req, role)
   614         title = self.schema.rschema(rtype).display_name(self.req, role)
   615         removejs = self.removejs % (peid, rtype,entity.eid)
   615         removejs = self.removejs % (peid, rtype,entity.eid)
   616         self.w(form.form_render(renderer=EntityInlinedFormRenderer(), divid=divid,
   616         self.w(form.form_render(renderer=EntityInlinedFormRenderer(), divid=divid,
   624             else:
   624             else:
   625                 rval = INTERNAL_FIELD_VALUE
   625                 rval = INTERNAL_FIELD_VALUE
   626             form.form_add_hidden('edit%s-%s:%s' % (role[0], rtype, peid), rval)
   626             form.form_add_hidden('edit%s-%s:%s' % (role[0], rtype, peid), rval)
   627         form.form_add_hidden(name='%s:%s' % (rtype, peid), value=entity.eid,
   627         form.form_add_hidden(name='%s:%s' % (rtype, peid), value=entity.eid,
   628                              id='rel-%s-%s-%s'  % (peid, rtype, entity.eid))
   628                              id='rel-%s-%s-%s'  % (peid, rtype, entity.eid))
   629         
   629 
   630     def keep_entity(self, entity, peid, rtype):
   630     def keep_entity(self, entity, peid, rtype):
   631         if not entity.has_eid():
   631         if not entity.has_eid():
   632             return True
   632             return True
   633         # are we regenerating form because of a validation error ?
   633         # are we regenerating form because of a validation error ?
   634         erroneous_post = self.req.data.get('formvalues')
   634         erroneous_post = self.req.data.get('formvalues')
   642 
   642 
   643 class InlineEntityCreationFormView(InlineEntityEditionFormView):
   643 class InlineEntityCreationFormView(InlineEntityEditionFormView):
   644     id = 'inline-creation'
   644     id = 'inline-creation'
   645     __select__ = (match_kwargs('peid', 'rtype')
   645     __select__ = (match_kwargs('peid', 'rtype')
   646                   & specified_etype_implements('Any'))
   646                   & specified_etype_implements('Any'))
   647     
   647     removejs = "removeInlineForm('%s', '%s', '%s')"
       
   648 
   648     def call(self, etype, peid, rtype, role='subject', **kwargs):
   649     def call(self, etype, peid, rtype, role='subject', **kwargs):
   649         """
   650         """
   650         :param etype: the entity type being created in the inline form
   651         :param etype: the entity type being created in the inline form
   651         :param peid: the parent entity's eid hosting the inline form
   652         :param peid: the parent entity's eid hosting the inline form
   652         :param rtype: the relation bridging `etype` and `peid`
   653         :param rtype: the relation bridging `etype` and `peid`