[Checkins] SVN: zope3org/trunk/src/zorg/multiform/ handle batch and sort of subforms

Stefan Martin s.martin at iwm-kmrc.de
Tue Apr 11 10:39:58 EDT 2006


Log message for revision 66854:
  handle batch and sort of subforms
  

Changed:
  U   zope3org/trunk/src/zorg/multiform/configure.zcml
  U   zope3org/trunk/src/zorg/multiform/gridform.py
  U   zope3org/trunk/src/zorg/multiform/gridform.txt
  U   zope3org/trunk/src/zorg/multiform/interfaces.py
  U   zope3org/trunk/src/zorg/multiform/multiform.py
  U   zope3org/trunk/src/zorg/multiform/tests.py

-=-
Modified: zope3org/trunk/src/zorg/multiform/configure.zcml
===================================================================
--- zope3org/trunk/src/zorg/multiform/configure.zcml	2006-04-11 14:38:18 UTC (rev 66853)
+++ zope3org/trunk/src/zorg/multiform/configure.zcml	2006-04-11 14:39:57 UTC (rev 66854)
@@ -15,6 +15,12 @@
           factory=".selection.FormLocationSelection"
           />
 
+ <adapter for="zope.interface.Interface
+               zope.schema.interfaces.IField"
+          factory=".sort.SchemaSorter"
+          provides=".interfaces.ISorter"
+          />
+
  <!-- namedtemplate for IParentAction -->
  <adapter factory=".multiform.render_submit_button" name="render" />
  

Modified: zope3org/trunk/src/zorg/multiform/gridform.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/gridform.py	2006-04-11 14:38:18 UTC (rev 66853)
+++ zope3org/trunk/src/zorg/multiform/gridform.py	2006-04-11 14:39:57 UTC (rev 66854)
@@ -1,10 +1,13 @@
-from interfaces import IGridForm,IGridItemForm
+
+from zope.component import getMultiAdapter
+from zope.formlib import namedtemplate
 from zope.interface import implements
-import multiform
-from zope.formlib import namedtemplate
 from zope.app.pagetemplate import ViewPageTemplateFile
 
+from interfaces import IGridForm, IGridItemForm, ISorter
+import multiform
 
+
 default_grid_template = namedtemplate.NamedTemplateImplementation(
     ViewPageTemplateFile('grid.pt'), IGridForm)
 
@@ -17,5 +20,114 @@
     template = namedtemplate.NamedTemplate('default')
 
 class GridFormBase(multiform.MultiFormBase):
+
     implements(IGridForm)
+    
     template = namedtemplate.NamedTemplate('default')
+
+    def __init__(self, context, request):
+        context = FilterMapping(context, request, self)
+        super(GridFormBase,self).__init__(context, request)
+        
+
+class FilterMapping(object):
+    
+    def __init__(self, context, request, form):
+        self.context = context
+        self.request = request
+        self.form = form
+        self.batch_start = request.form.get(
+                           '%s.handle.batch_start' % form.prefix, None)
+        self.batch_size = request.form.get(
+                           '%s.handle.batch_size' % form.prefix, None)
+        self.sort_on = request.form.get(
+                           '%s.handle.sort_on' % form.prefix, None)
+        self.sort_reverse = request.form.get(
+                           '%s.handle.sort_reverse' % form.prefix, None)
+
+    def sortAllKeys(self):
+        sorter = None
+        if self.sort_on:
+            sortName = self.sort_on
+            sortField = None
+            for field in self.form.itemFormFactory.form_fields:
+                if field.__name__ == sortName:
+                    sortField = field
+                    break
+            if sortField:
+                sorter = getMultiAdapter((sortField.field.interface,
+                                          sortField.field),ISorter)
+        if sorter:
+            items = sorter.sort(self.context.items())
+            if self.sort_reverse:
+                items.reverse()
+            keys = []
+            for key, value in items:
+                yield key
+        else:
+            for key in self.context.keys():
+                yield key
+
+    def keys(self):
+        sortKeys = self.sortAllKeys()
+        batch_start = self.batch_start or 0
+        batch_size = self.batch_size or 0
+        if not self.batch_size:
+            if not batch_start:
+                for k in sortKeys:
+                    yield k
+                raise StopIteration
+            batch_end = None
+        else:
+            batch_end = batch_start + batch_size
+        for i, key in enumerate(sortKeys):
+            if batch_end is not None and i >= batch_end:
+                return
+            if i >= batch_start:
+                yield key
+
+    def values(self):
+        for k in self.keys():
+            yield self.context[k]
+
+    def items(self):
+        for k in self.keys():
+            yield k, self.context[k]
+
+    def __iter__(self):
+        return iter(self.keys())
+
+    def __getitem__(self, key):
+        '''See interface `IReadContainer`'''
+        if key in self.keys():
+            return self.context[key]
+        else:
+            raise KeyError, key
+
+    def get(self, key, default=None):
+        '''See interface `IReadContainer`'''
+        try:
+            return self.__getitem__(key)
+        except KeyError:
+            return default
+
+    def __len__(self):
+        '''See interface `IReadContainer`'''
+        return len(self.keys())
+
+    def __contains__(self, key):
+        '''See interface `IReadContainer`'''
+        return key in self.keys()
+
+    has_key = __contains__
+
+    def __setitem__(self, key, object):
+        '''See interface `IWriteContainer`'''
+        self.context.__setitem__(key, object)
+
+    def __delitem__(self, key):
+        '''See interface `IWriteContainer`'''
+        if key in self.keys():
+            self.context.__delitem__(key)
+        else:
+            raise KeyError, key

Modified: zope3org/trunk/src/zorg/multiform/gridform.txt
===================================================================
--- zope3org/trunk/src/zorg/multiform/gridform.txt	2006-04-11 14:38:18 UTC (rev 66853)
+++ zope3org/trunk/src/zorg/multiform/gridform.txt	2006-04-11 14:39:57 UTC (rev 66854)
@@ -25,7 +25,7 @@
     ...         self.name = name
     ...         self.__name__= name
 
-    >>> orderMapping = dict([('n%s'%k,Order(k,name='n%s'%k)) for k in range(2)])
+    >>> orderMapping = dict([('n%s'%k,Order(k,name='n%s'%k)) for k in range(4)])
 
 Now we use the ``GridForm`` as a base class to display orders in
 tabular form. Additionally to the IOrder schema the ISelection schema
@@ -115,6 +115,7 @@
     <div><input ... name="form.n1.selected" type="checkbox" ...  /></div>
     <div>1</div>
     <div>n1</div>
+    ...
     </div>
 
 Also the edit action should be available.
@@ -141,6 +142,7 @@
     <div><input... checked="checked" ... name="form.n1.selected" ... /></div>
     <div>1</div>
     <div>n1</div>
+    ...
     </div>
 
 By using the Edit action we can now switch all selected item forms to
@@ -150,6 +152,8 @@
     >>> request.form['form.actions.edit']=u''
     >>> request.form['form.n0.selected.used']=u''
     >>> request.form['form.n1.selected']=u'on'
+    >>> request.form['form.n2.selected.used']=u''
+    >>> request.form['form.n3.selected.used']=u''
     >>> gf = OrdersForm(orderMapping,request)
     >>> res = gf()
     >>> ISelection(gf.subForms['n1'].context).selected
@@ -164,6 +168,7 @@
     <div><input... checked="checked" ... name="form.n1.selected" ... /></div>
     <div>1</div>
     <div><input... name="form.n1.name" ...</div>
+    ...
     </div>
 
 Also the edit action should be disabled now and the save action should
@@ -189,4 +194,86 @@
     >>> request.form['form.n1.selected.used']=u''
     >>> request.form['form.n1.actions.singleedit']=u''
     >>> gf = OrdersForm(orderMapping,request)
-    >>> res = gf()  
+    >>> res = gf()
+
+The gridform class is able to handle batch_start and batch_size. Let us reduce
+the output.
+
+    >>> request = TestRequest()
+    >>> request.form['form.handle.batch_start']=1
+    >>> request.form['form.handle.batch_size']=2
+    >>> gf = OrdersForm(orderMapping,request)
+    >>> gf.update()
+    >>> print gf.render()
+    <div>
+    <div><input ... name="form.n1.selected" type="checkbox" ...  /></div>
+    <div>1</div>
+    <div>n1</div>
+    </div>
+    <div>
+    <div><input ... name="form.n2.selected" type="checkbox" ...  /></div>
+    <div>2</div>
+    <div>n2</div>
+    </div>    
+
+Check the results of fraktal informations about batch_size and batch_start:
+
+    >>> request = TestRequest()
+    >>> request.form['form.handle.batch_start']=1
+    >>> gf = OrdersForm(orderMapping,request)
+    >>> gf.update()
+    >>> sorted([name for name in gf.subForms])
+    ['n1', 'n2', 'n3']
+    >>> request = TestRequest()
+    >>> request.form['form.handle.batch_size']=2
+    >>> gf = OrdersForm(orderMapping,request)
+    >>> gf.update()
+    >>> sorted([name for name in gf.subForms])
+    ['n0', 'n1']
+
+
+Sorting
+-------
+We can sort the grid with the informations field name (string) and
+reverse (bool).
+
+    >>> class Orders2Form(gridform.GridFormBase):
+    ...     itemFormFactory=OrderForm
+    ...     def template(self):
+    ...         res = u''
+    ...         for form in self.getForms():
+    ...             res += '<div>%s</div>\n' % form.render()
+    ...         return res
+    ...         
+    ...     @form.action('Cancel',condition=multiform.isFormInputMode)
+    ...     def handle_cancel_action(self, action, data):
+    ...         for form in self.subForms.values():
+    ...             form.newInputMode = False
+
+    >>> orderMapping2 = dict([('n%s'%k,Order(4-k,name='n%s'%k)) for k
+    ... in range(4)])
+
+We sort the forms by the value of the column name
+    
+    >>> request = TestRequest()
+    >>> request.form['form.handle.sort_on']=u'name'
+    >>> gf = Orders2Form(orderMapping2,request)
+    >>> gf.update()
+    >>> [(form.context.identifier,
+    ...   form.context.name) for form in gf.getForms()]
+    [(4, 'n0'), (3, 'n1'), (2, 'n2'), (1, 'n3')]
+
+and reserve.
+
+    >>> request = TestRequest()
+    >>> request.form['form.handle.sort_on']=u'name'
+    >>> request.form['form.handle.sort_reverse']=u'on'
+    >>> gf = Orders2Form(orderMapping2,request)
+    >>> gf.update()
+    >>> [(form.context.identifier,
+    ...   form.context.name) for form in gf.getForms()]
+    [(1, 'n3'), (2, 'n2'), (3, 'n1'), (4, 'n0')]
+
+TODO:  
+-----
+- test singleedit, singlesave
\ No newline at end of file

Modified: zope3org/trunk/src/zorg/multiform/interfaces.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/interfaces.py	2006-04-11 14:38:18 UTC (rev 66853)
+++ zope3org/trunk/src/zorg/multiform/interfaces.py	2006-04-11 14:39:57 UTC (rev 66854)
@@ -3,6 +3,7 @@
 from zope import schema
 from zope.formlib.i18n import _
 
+
 class IMultiForm(Interface):
 
     """multiform"""
@@ -11,16 +12,20 @@
 
     """a sub form for an item of a multiform"""
 
+
 class IGridItemForm(IItemForm):
 
     """an form for an item of a grid form"""
 
+
 class IGridForm(IMultiForm):
 
     """a special grid multiform"""
 
+
 class IItemAction(IAction):
     """a item action"""
+
     
 class IParentAction(IAction):
     """a parent action"""
@@ -32,6 +37,13 @@
 
     selected = schema.Bool(title=_(u'Selected'),default=False)
 
+
 class IFormLocation(Interface):
 
     __form_name__ = Attribute('The unique name of the item in a multiform')
+
+
+class ISorter(Interface):
+
+    def sort(items):
+        """return the items sorted. items are (key,value) tuples"""

Modified: zope3org/trunk/src/zorg/multiform/multiform.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/multiform.py	2006-04-11 14:38:18 UTC (rev 66853)
+++ zope3org/trunk/src/zorg/multiform/multiform.py	2006-04-11 14:39:57 UTC (rev 66854)
@@ -140,22 +140,23 @@
     implements(IMultiForm)
     itemFormFactory = ItemFormBase
     subForms={}
+    subFormsList = []
     form_fields = []
     actions = []
     subActionNames = []
     subFormInputMode = {}
     selection = []
     actions = []
-    
+
     def update(self):
         self.checkInputMode()
         self.updateSelection()
         super(MultiFormBase,self).update()
         hasErrors = False
-        for form in self.subForms.values():
+        for form in self.getForms():
             form.update()
         refresh = False
-        for form in self.subForms.values():
+        for form in self.getForms():
             if form.newInputMode is not None:
                 newInputMode = form.newInputMode
                 context = self.context[form.context.__name__]
@@ -168,7 +169,6 @@
 
     def setUpWidgets(self, *args, **kw):
         super(MultiFormBase,self).setUpWidgets(*args,**kw)
-        self.subForms = {}
         self.setUpForms(*args, **kw)
 
     def setUpForm(self, name, item, inputMode, *args, **kw):
@@ -185,14 +185,21 @@
         self.subForms[name] = subForm
 
     def setUpForms(self, *args, **kw):
-        for name,item in self.context.items():
+        self.subForms = {}
+        self.subFormsList = []
+        for name, item in self.context.items():
             inputMode = self.subFormInputMode.get(name,self.itemFormFactory.inputMode)
             self.setUpForm(name, item, inputMode)
+            self.subFormsList.append(name)
         self.refreshSubActionNames()
 
+    def getForms(self):
+        for name in self.subFormsList:
+            yield self.subForms[name]
+
     def refreshSubActionNames(self):
         availableActions = set()
-        for subForm in self.subForms.values():
+        for subForm in self.getForms():
             availableActions.update([action.__name__ for action in \
                                      subForm.availableParentActions()])
         self.subActionNames = []
@@ -263,7 +270,7 @@
                 action.__name__ = name
                 yield action
 
-    
+
 class SelectionForm(form.FormBase):
     
     def __init__(self, context, request, form_fields):

Modified: zope3org/trunk/src/zorg/multiform/tests.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/tests.py	2006-04-11 14:38:18 UTC (rev 66853)
+++ zope3org/trunk/src/zorg/multiform/tests.py	2006-04-11 14:39:57 UTC (rev 66854)
@@ -11,6 +11,7 @@
 import gridform
 import multiform
 import selection
+import sort
 from zope.formlib import form
 
 def setUp(test):
@@ -70,7 +71,12 @@
         [interfaces.IFormLocation],
         interfaces.ISelection
         )
-    
+    component.provideAdapter(
+        sort.SchemaSorter,
+        [zope.interface.Interface,
+         zope.schema.interfaces.IField],
+        interfaces.ISorter
+        )    
     component.provideAdapter(gridform.default_grid_template,
                              name="default")
     component.provideAdapter(gridform.default_griditem_template,



More information about the Checkins mailing list