Work in progress: reporter.batch

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1217 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-05-19 09:34:57 +00:00
parent 3d9908f2d5
commit 7a09a7d9df
6 changed files with 229 additions and 9 deletions

View file

@ -489,15 +489,26 @@ div.row div.label {
clear: both;
}
div.row span.error {
background: red;
div.error {
background: #ff80a0;
color: white;
font-weight: bold;
padding: 0.1em 0.5em 0.1em 0.5em; /* Same as .itemViews */
border: 1px solid red; /* Same as .itemViews */
margin: 0;
float: left;
clear: both;
}
div.summary {
background: #c8c4ff;
font-weight: bold;
padding: 0.1em 0.5em 0.1em 0.5em; /* Same as .itemViews */
border: 1px solid #6478b0; /* Same as .itemViews */
margin: 0;
margin-top: 1em;
}
/*
div.row div.error:before {
content: "\2190 "; /* Left pointing arrow */

View file

@ -12,15 +12,47 @@ TO DO...
A Basic API for Reports and Listings
====================================
Batching
--------
We'll use a fairly simple Iterable:
>>> it = xrange(14)
>>> from cybertools.reporter.batch import Batch
>>> b = Batch(it, size=5, overlap=1, orphan=2)
>>> b.items
[0, 1, 2, 3, 4]
>>> b.getIndexRelative(1)
1
>>> b.getIndexAbsolute(-1)
2
>>> b = Batch(it, 2, size=5, overlap=1, orphan=2)
>>> b.items
[8, 9, 10, 11, 12, 13]
We are now ready to use the corresponding browser view:
>>> from zope.publisher.browser import TestRequest
>>> form = dict(b_page=1, b_size=4)
>>> request = TestRequest(form=form)
>>> from cybertools.reporter.browser.batch import BatchView
>>> bview = BatchView(it, request)
The real reporting stuff
------------------------
>>> from cybertools.reporter.data import DataSource
>>> from cybertools.reporter.interfaces import IResultSet
>>> from cybertools.reporter.example.interfaces import IContactsDataSource
>>> from cybertools.reporter.example.contact import Contacts
Let's start with the Person class from the example package - we will
then provide a listing of persons...
>>> from cybertools.organize.party import Person
>>> from cybertools.reporter.example.interfaces import IContactsDataSource
>>> from cybertools.reporter.example.contact import Contacts
>>> from datetime import date
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
@ -47,6 +79,4 @@ result set and splitting a result into batches.
Sorting
-------
Batching
--------

78
reporter/batch.py Normal file
View file

@ -0,0 +1,78 @@
#
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Batching implementation.
$Id$
"""
import itertools
from zope.interface import implements
from interfaces import IBatch
class Batch(object):
lastPage = False
def __init__(self, iterable, pageIndex=0, size=20, overlap=0, orphan=0):
self.iterable = list(iterable)
self.pageIndex = pageIndex
self.start = pageIndex * (size - overlap)
self.size = self.actualSize = size
self.overlap = overlap
self.orphan = orphan
length = len(self.iterable)
self.pages = range(0, length, size-overlap)
lastPage = self.pages[-1]
lastLen = length - lastPage
if lastLen <= orphan + overlap:
del self.pages[-1]
if pageIndex == len(self.pages) - 1: #we're on the last page
self.actualSize = size + lastLen #take over the orphans
if pageIndex >= len(self.pages) or pageIndex < 0:
self.items = []
else:
self.items = self.iterable[self.start:self.start+self.actualSize]
def __getitem__(self, idx):
return self.items[idx]
def next(self):
for item in self.items:
yield item
def __len__(self):
return len(self.items)
def getIndexRelative(self, ridx=1):
idx = self.pageIndex + ridx
if idx < 0:
return 0
if idx >= len(self.pages):
return len(self.pages) - 1
return idx
def getIndexAbsolute(self, idx=0):
if idx < 0:
idx = len(self.pages) + idx
if idx < 0 or idx >= len(self.pages):
return None
return idx

60
reporter/browser/batch.py Normal file
View file

@ -0,0 +1,60 @@
#
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
A browser view class for batching to be used by a macro or some other
HTML providing template.
$Id$
"""
from cybertools.reporter.batch import Batch
class BatchView(object):
def __init__(self, context, request):
self.context = context
self.request = request
form = request.form
page = int(form.get('b_page', 1))
size = int(form.get('b_size', 20))
overlap = int(form.get('b_overlap', 0))
orphan = int(form.get('b_orphan', 0))
self.batch = Batch(context, page-1, size, overlap, orphan)
def items(self):
return setupUrlParams(self.batch.items)
def first(self):
return setupUrlParams(self.batch.getIndexAbsolute(0))
def last(self):
return setupUrlParams(self.batch.getIndexAbsolute(-1))
def previous(self):
return setupUrlParams(self.batch.getIndexRelative(1))
def next(self):
return setupUrlParams(self.batch.getIndexRelative(-1))
def setupUrlParams(self, page):
return ('?b_page=%i&b_size=%i&b_overlap=%i&b_orphan=%i'
% (page, self.size, self.overlap, self.orphan) )

View file

@ -26,7 +26,47 @@ import zope
from zope.interface import Interface, Attribute
# result set
# iterable stuff for batching, sorting, filtering of results
class IBatch(Interface):
""" Represents a part (sort of a slice) of an iterable.
"""
iterable = Attribute(u'The iterable this batch belongs to')
start = Attribute(u'The current start index of the batch in the parent iterable')
def __getitem__(idx):
""" Return the item at index idx.
"""
def next():
""" Return the next item in the batch. Raise StopIteration if
the end of the batch is reached.
"""
def __len__():
""" Return the number of items in the batch.
"""
def getIndexRelative(relativePageNumber):
""" Return the absolute page index based on the current page of
the batch object.
Using +1 or -1 retrieves the next or previous batch.
If a page before the first one is addressed return 0,
if a page after the last one is addressed return the index
of the last page.
"""
def getIndexAbsolute(pageNumber):
""" Return the absolute page index.
0 addresses the first batch page, -1 the last.
Return None if the corresponding page does not exist.
"""
# result sets, rows, cells...
class IResultSet(Interface):
"""A sequence of rows provided by a data source, report or

View file

@ -1,6 +1,6 @@
# $Id$
import unittest
import unittest, doctest
from zope.testing.doctestunit import DocFileSuite
from zope.app.testing import ztapi
from zope.interface.verify import verifyClass
@ -18,9 +18,10 @@ class TestReporter(unittest.TestCase):
def test_suite():
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
return unittest.TestSuite((
unittest.makeSuite(TestReporter),
DocFileSuite('README.txt'),
DocFileSuite('README.txt', optionflags=flags),
))
if __name__ == '__main__':