[Checkins] SVN: zope3org/trunk/src/zorg/multiform/ implemented tests and actions

Bernd Dorn bernd.dorn at fhv.at
Sun Apr 9 16:38:50 EDT 2006


Log message for revision 66751:
  implemented tests and actions

Changed:
  U   zope3org/trunk/src/zorg/multiform/README.txt
  U   zope3org/trunk/src/zorg/multiform/actions.txt
  U   zope3org/trunk/src/zorg/multiform/interfaces.py
  U   zope3org/trunk/src/zorg/multiform/multiform.py

-=-
Modified: zope3org/trunk/src/zorg/multiform/README.txt
===================================================================
--- zope3org/trunk/src/zorg/multiform/README.txt	2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/README.txt	2006-04-09 20:38:50 UTC (rev 66751)
@@ -3,7 +3,7 @@
 ===================
 
 This Package provides an API to handle multiple forms with matching
-form fields on multiple items. The cration of multiforms is derived
+form fields on multiple items. The creation of multiforms is derived
 from the Form class of the formlib package.
 
     >>> from zope import interface, schema
@@ -83,165 +83,3 @@
     ...
     </div>
 
-In order to define a save action on the multiform we have to define a
-parent action on our OrderForm. A parent action is rendered only one
-time in the parent multiform, but applied to all subforms.
-
-    >>> from multiform import multiform
-    >>> class OrderForm2(ItemFormBase):
-    ...     form_fields = form.Fields(IOrder,omit_readonly=False,
-    ...     render_context=True)
-    ...         
-    ...     @multiform.parentAction(u"Save",condition=form.haveInputWidgets)
-    ...     def handle_save_action(self, action, data):
-    ...         form.applyChanges(self.context, self.form_fields,
-    ...         data, self.adapters)
-    ...         
-    ...     def template(self):
-    ...         return '\n<div>%s</div>\n' % '</div><div>'.join([w() for w in
-    ...     self.widgets])
-
-
-Now we have to set the factory on the OrdersForm.
-
-    >>> class OrdersForm2(MultiFormBase):
-    ...     itemFormFactory=OrderForm2
-    ...     def template(self):
-    ...         res = u''
-    ...         names = sorted(self.subForms.keys())
-    ...         for name in names:
-    ...             res += '<div>%s</div>\n' % self.subForms[name].render()
-    ...         return res
-
-
-
-    >>> pf = OrdersForm2(orderMapping,request)
-    >>> pf.setUpWidgets()
-    >>> action = [action for action in pf.subForms['1'].actions][0]
-    >>> action
-    <multiform.multiform.ParentAction object at ...>
-
-All available parent action names of the subforms are available through the
-subActions attribute of the multi form.
-
-    >>> pf.subActionNames
-    [u'actions.save']
-
-The name of the action is without the item key, because it is applied
- to all items.
-
-    >>> print action.__name__
-    actions.save
-
-    >>> request = TestRequest()
-    >>> orderMapping = dict([(str(k),Order(k,name='n%s'%k)) for k in range(2)])
-    >>> request.form[pf.prefix + '.' + action.__name__]=u''
-    >>> print OrdersForm2(orderMapping,request)()
-    Traceback (most recent call last):
-    ...
-    FormError: ('No input', 'name')
-
-Ups, we have an error because we didn't provide the input data on the
-request. The form requires to have all input fields in the request if
-an action should be supplied.
-
-Let's supply request Data.
-
-    >>> for i in range(2):
-    ...     request.form['form.%s.name' % i]='new name %s' % i
-    ...     request.form['form.%s.identifier' % i]= i
-    >>> print OrdersForm2(orderMapping,request)()
-    <div>
-    <div... value="new name 0" ...
-    <div... value="new name 1" ...
-    </div>
-
-The above example uses inputwidgets for all editable fields in the
-forms. In the next example we implement a multiform which uses
-displaywidgets per default. Inputwidgets should only be used if the
-'Edit' action is called.
-
-So let us define a new specialized item form class, which defines a
-new parent action called ``Edit``.
-
-    >>> def haveNoInputWidgets(f,action):
-    ...     return not form.haveInputWidgets(f,action)
-
-    >>> class OrderForm3(ItemFormBase):
-    ...     
-    ...     def __init__(self,context,request,parentForm):
-    ...         super(OrderForm3,self).__init__(context,request,parentForm)
-    ...         self.form_fields = form.Fields(IOrder,omit_readonly=False,
-    ...         render_context=True,for_display=True)
-    ...         
-    ...         
-    ...     @multiform.parentAction(u"Save",condition=form.haveInputWidgets)
-    ...     def handle_save_action(self, action, data):
-    ...         import pdb;pdb.set_trace()
-    ...         for field in self.form_fields:
-    ...             field.for_display=False
-    ...         form.setUpWidgets() 
-    ...         form.applyChanges(self.context, self.form_fields,
-    ...         data, self.adapters)
-    ...         
-    ...     @multiform.parentAction('Edit',condition=haveNoInputWidgets)
-    ...     def handle_edit_action(self, action, data):
-    ...         for field in self.form_fields:
-    ...             field.for_display=False
-    ...         self.form_reset=True
-    ...     def template(self):
-    ...         return '\n<div>%s</div>\n' % '</div><div>'.join([w() for w in
-    ...     self.widgets])
-
-
-    >>> class OrdersForm3(OrdersForm2):
-    ...     itemFormFactory=OrderForm3
-
-So in our new form all widgets are display widgets per default
-
-    >>> request = TestRequest()
-    >>> pf = OrdersForm3(orderMapping,request)
-    >>> print pf()
-    <div>
-    <div>0</div><div>new name 0</div>
-    </div>
-    <div>
-    <div>1</div><div>new name 1</div>
-    </div>
-
-And the save action should not be available, due to the reason that there
-are no input widgets in the sub forms.
-
-    >>> pf.subActionNames
-    [u'actions.edit']
-
-Now let's call the edit action to set the widgets to input widgets.
-
-    >>> request.form['form.actions.edit']=u''
-    >>> pf =  OrdersForm3(orderMapping,request)
-    >>> print pf()
-    <div>
-    <div...<input class="textType" ... value="new name 0" ...
-    </div>
-    <div>
-    <div...<input class="textType" ... value="new name 1" ...
-
-Now only the save action should be available.
-
-    >>> pf.subActionNames
-    [u'actions.save']
-
-Let us save some data.
-
-    >>> request = TestRequest()
-    >>> request.form['form.actions.save']=u''
-    >>> for i in range(2):
-    ...     request.form['form.%s.name' % i]='newer name %s' % i
-    ...     request.form['form.%s.identifier' % i]= i
-    >>> print OrdersForm3(orderMapping,request)()
-
-
-TODO:
-
-- encode prefix, do we have to do it?
-

Modified: zope3org/trunk/src/zorg/multiform/actions.txt
===================================================================
--- zope3org/trunk/src/zorg/multiform/actions.txt	2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/actions.txt	2006-04-09 20:38:50 UTC (rev 66751)
@@ -1,8 +1,18 @@
-So let us define a new specialized item form class, which defines a
-new parent action called ``Edit``.
+===================
+ Multiform Actions
+===================
 
+The multiform package defines a new type of action called
+ParentAction. A parent action is rendered only one time in the parent
+multiform, but applied to all subforms.
 
+In this example we create a specialized item form class, which defines
+a new parent action called ``Save``. Additionally two standard actions
+are defined in the multiform (parent) class called ``Edit`` and
+``Cancel```.
+
     >>> from multiform.multiform import ItemFormBase,MultiFormBase
+    >>> from zope.app.form.interfaces import IInputWidget
     >>> from zope.formlib import form
     >>> from multiform import multiform
     >>> from zope.publisher.browser import TestRequest
@@ -19,49 +29,80 @@
 
     >>> orderMapping = dict([(str(k),Order(k,name='n%s'%k)) for k in range(2)])
 
-    >>> def haveNoInputWidgets(f,action):
-    ...     return not form.haveInputWidgets(f,action)
+    >>> def isFormDisplayMode(f,action):
+    ...     return not f.inputMode
+    
+    >>> def isFormInputMode(f,action):
+    ...     return f.inputMode
 
-    >>> class OrderForm3(ItemFormBase):
+    >>> def isParentFormInputMode(f,action):
+    ...     return f.parentForm.inputMode
+
+    >>> def hasInputWidgets(f,action):
+    ...     if form.haveInputWidgets(f,action):
+    ...         return True
+    ...     if ISubmittedAction.providedBy(action):
+    ...         tmpForm = f.parentForm.itemFormFactory(f.context,
+    ...         f.request,f.parentForm)
+    ...         tmpForm.setPrefix(f.prefix)
+    ...         hasInput = True
+    ...         form_prefix = f.prefix +'.'
+    ...         for field in tmpForm.form_fields:
+    ...             field.for_display=False
+    ...         tmpForm.setUpWidgets()
+    ...         for input, widget in \
+    ...         tmpForm.widgets.__iter_input_and_widget__():
+    ...             if input and IInputWidget.providedBy(widget):
+    ...                 name = form._widgetKey(widget, form_prefix)
+    ...                 if not widget.hasInput():
+    ...                     hasInput = False
+    ...                     break
+    ...         return hasInput
+    ...     return False
+
+    >>> class OrderForm(ItemFormBase):
+    ...     inputMode=False
     ...     
     ...     def __init__(self,context,request,parentForm):
-    ...         super(OrderForm3,self).__init__(context,request,parentForm)
+    ...         super(OrderForm,self).__init__(context,request,parentForm)
     ...         self.form_fields = form.Fields(IOrder,omit_readonly=False,
-    ...         render_context=True,for_display=True)
+    ...         render_context=True)
     ...         
-    ...     @multiform.parentAction(u"Save",condition=form.haveInputWidgets)
+    ...     @multiform.parentAction(u"Save",condition=isParentFormInputMode,
+    ...     inputMode=True)
     ...     def handle_save_action(self, action, data):
-    ...         import pdb;pdb.set_trace()
-    ...         for field in self.form_fields:
-    ...             field.for_display=False
-    ...         form.setUpWidgets() 
     ...         form.applyChanges(self.context, self.form_fields,
     ...         data, self.adapters)
+    ...         self.parentForm.newInputMode=False
     ...         
-    ...     @multiform.parentAction('Edit',condition=haveNoInputWidgets)
-    ...     def handle_edit_action(self, action, data):
-    ...         for field in self.form_fields:
-    ...             field.for_display=False
-    ...         self.form_reset=True
     ...         
     ...     def template(self):
     ...         return '\n<div>%s</div>\n' % '</div><div>'.join([w() for w in
     ...     self.widgets])
 
 
-    >>> class OrdersForm3(MultiFormBase):
-    ...     itemFormFactory=OrderForm3
+    >>> class OrdersForm(MultiFormBase):
+    ...     itemFormFactory=OrderForm
     ...     def template(self):
     ...         res = u''
     ...         names = sorted(self.subForms.keys())
     ...         for name in names:
     ...             res += '<div>%s</div>\n' % self.subForms[name].render()
     ...         return res
+    ...     
+    ...     @form.action('Edit',condition=isFormDisplayMode)
+    ...     def handle_edit_action(self, action, data):
+    ...         self.newInputMode=True
+    ...         
+    ...     @form.action('Cancel',condition=isFormInputMode)
+    ...     def handle_cancel_action(self, action, data):
+    ...         self.newInputMode=False
 
+
 So in our new form all widgets are display widgets per default
 
     >>> request = TestRequest()
-    >>> pf = OrdersForm3(orderMapping,request)
+    >>> pf = OrdersForm(orderMapping,request)
     >>> print pf()
     <div>
     <div>0</div><div>n0</div>
@@ -74,12 +115,14 @@
 are no input widgets in the sub forms.
 
     >>> pf.subActionNames
-    [u'actions.edit']
+    []
+    >>> [action.__name__ for action in pf.availableActions()]
+    [u'form.actions.edit']
 
 Now let's call the edit action to set the widgets to input widgets.
 
     >>> request.form['form.actions.edit']=u''
-    >>> pf =  OrdersForm3(orderMapping,request)
+    >>> pf =  OrdersForm(orderMapping,request)
     >>> print pf()
     <div>
     <div...<input class="textType" ... value="n0" ...
@@ -87,17 +130,69 @@
     <div>
     <div...<input class="textType" ... value="n1" ...
 
-Now only the save action should be available.
+Now the save action should be available in the subActionNames and
+the cancel action in the multiform actions.
 
     >>> pf.subActionNames
-    [u'actions.save']
+    [u'form.actions.save']
+    >>> [a.__name__ for a in pf.availableActions()]
+    [u'form.actions.cancel']
 
-Let us save some data.
 
+Now Let us save some data.
+
     >>> request = TestRequest()
     >>> request.form['form.actions.save']=u''
     >>> for i in range(2):
     ...     request.form['form.%s.name' % i]='newer name %s' % i
     ...     request.form['form.%s.identifier' % i]= i
-    >>> print OrdersForm3(orderMapping,request)()
+    >>> pf =  OrdersForm(orderMapping,request)
+    >>> result = pf()
 
+After the form is called, the changes are applied to the objects. 
+    >>> [obj.name for obj in orderMapping.values()]
+    [u'newer name 1', u'newer name 0']
+
+Due to the reason the save handler sets the inputMode to False,
+only display widgets are rendered in the results
+
+    >>> print result
+    <div>
+    <div>0</div><div>newer name 0</div>
+    </div>
+    <div>
+    <div>1</div><div>newer name 1</div>
+    </div>
+
+Now we should only have the edit action be available, which is a
+multiform action, therefore not contained in the subActionNames
+
+    >>> pf.subActionNames
+    []
+    >>> [a.__name__ for a in pf.availableActions()]
+    [u'form.actions.edit']
+
+Now Let us cancel the edit mode.
+
+    >>> request = TestRequest()
+    >>> request.form['form.actions.cancel']=u''
+    >>> for i in range(2):
+    ...     request.form['form.%s.name' % i]='next name %s' % i
+    ...     request.form['form.%s.identifier' % i]= i
+    >>> pf =  OrdersForm(orderMapping,request)
+    >>> result = pf()
+
+After the form is called, the objects are left unchanged. And the form
+should be in display mode again.
+
+    >>> [obj.name for obj in orderMapping.values()]
+    [u'newer name 1', u'newer name 0']
+
+    >>> print result
+    <div>
+    <div>0</div><div>newer name 0</div>
+    </div>
+    <div>
+    <div>1</div><div>newer name 1</div>
+    </div>
+

Modified: zope3org/trunk/src/zorg/multiform/interfaces.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/interfaces.py	2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/interfaces.py	2006-04-09 20:38:50 UTC (rev 66751)
@@ -8,3 +8,5 @@
 
 class IParentAction(IAction):
     """a parent action"""
+
+

Modified: zope3org/trunk/src/zorg/multiform/multiform.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/multiform.py	2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/multiform.py	2006-04-09 20:38:50 UTC (rev 66751)
@@ -8,6 +8,7 @@
 from zope.formlib.i18n import _
 from interfaces import IMultiForm, IParentAction
 from zope import interface
+        
 
 class ParentAction(form.Action):
 
@@ -15,24 +16,28 @@
     is applied to all subForms"""
     
     implements(IParentAction)
-    
+    def __init__(self, label, **options):
+        self.inputMode = options.pop('inputMode',None)
+        super(ParentAction,self).__init__(label,**options)
+        
+        
     def __get__(self, form, class_=None):
         if form is None:
             return self
         result = self.__class__.__new__(self.__class__)
         result.__dict__.update(self.__dict__)
         result.form = form
-        #result.__name__ = form.prefix + '.' + result.__name__
+        result.__name__ = form.parentForm.prefix + '.' + result.__name__
         interface.alsoProvides(result, IBoundAction)
         return result
 
     def submitted(self):
         # override to find the matching prefix
         if not self.available():
-            return False
-        form = self.form.parentForm
-        name = "%s.%s" % (form.prefix, self.__name__)
-        return name in form.request.form
+            res = False
+        else:
+            res =  self.__name__ in self.form.request
+        return res
 
 
 class parentAction(form.action):
@@ -46,6 +51,7 @@
 class ItemFormBase(form.FormBase):
 
     parentForm = None
+    inputMode = None
 
     def __init__(self,context,request,parentForm):
         super(ItemFormBase,self).__init__(context,request)
@@ -64,6 +70,9 @@
         actions= form.availableActions(self, actions)
         return actions
 
+
+
+
 class MultiFormBase(form.FormBase):
 
 
@@ -72,31 +81,39 @@
     form_fields = []
     actions = []
     subActionNames = []
+    inputMode = None
+    newInputMode = None
     
     def update(self):
+        self.initInputMode()
+        self.checkInputMode()
         super(MultiFormBase,self).update()
         subFormReset = False
+        hasErrors = False
         for form in self.subForms.values():
             form.update()
-            if form.form_result is None:
-                if form.form_reset:
-                    subFormReset=True
-                    form.resetForm()
-                    form.form_reset=False
-        if subFormReset:
-            self.refreshSubActionNames()
+            hasErrors = hasErrors or form.errors
+        if hasErrors:
+            self.newInputMode=None
+        if self.newInputMode is not None:
+            self.setInputMode(self.newInputMode)
+            self.setUpForms(ignore_request=True)
 
-
     def setUpWidgets(self, *args, **kw):
         super(MultiFormBase,self).setUpWidgets(*args,**kw)
         self.subForms = {}
         self.setUpForms(*args, **kw)
 
     def setUpForms(self, *args, **kw):
-
+        
         for name,item in self.context.items(): 
             prefix = (self.prefix and self.prefix+'.' or '') + name
             subForm = self.itemFormFactory(item,self.request,self)
+            if self.inputMode is not None and not self.inputMode:
+                forceInputs = getattr(self.itemFormFactory,'forceInputs',[])
+                for field in subForm.form_fields:
+                    if field.__name__ not in forceInputs:
+                        field.for_display=True
             subForm.setPrefix(prefix)
             subForm.setUpWidgets(*args, **kw)
             self.subForms[name] = subForm
@@ -110,7 +127,32 @@
         self.subActionNames = []
         if hasattr(self.itemFormFactory,'actions'):
             for action in self.itemFormFactory.actions:
-                if action.__name__ in availableActions:
-                    self.subActionNames.append(action.__name__)
+                name = '%s.%s' % (self.prefix,action.__name__)
+                if name in availableActions:
+                    self.subActionNames.append(name)
                     
             
+    def setInputMode(self,v=True):
+        if self.inputMode != v:
+            self.inputMode = v
+            for form in self.subForms.values():
+                form.form_reset=True
+
+
+    def initInputMode(self):
+        self.inputMode = self.itemFormFactory.inputMode
+        if self.inputMode is None:
+            self.inputMode = False
+            for field in self.itemFormFactory.form_fields:
+                if not field.for_display:
+                    self.inputMode=True
+                    break
+
+    def checkInputMode(self):
+        for action in self.itemFormFactory.actions:
+            name = '%s.%s' % (self.prefix,action.__name__)
+            if name in self.request.form and action.inputMode \
+               is not None:
+                self.setInputMode(action.inputMode)
+            
+                



More information about the Checkins mailing list