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:
parent
3d9908f2d5
commit
7a09a7d9df
6 changed files with 229 additions and 9 deletions
|
@ -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 */
|
||||
|
|
|
@ -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
78
reporter/batch.py
Normal 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
60
reporter/browser/batch.py
Normal 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) )
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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__':
|
||||
|
|
Loading…
Add table
Reference in a new issue