changeset 1810:21baa15e38ea

autofilters for databrowser widget. Patch by Johannes Berg.
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Sat, 24 Feb 2007 16:48:08 +0100
parents 03fbdd327f1f
children b7645fb02d1d
files MoinMoin/util/dataset.py MoinMoin/widget/browser.py docs/CHANGES
diffstat 3 files changed, 126 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/util/dataset.py	Sat Feb 24 15:56:40 2007 +0100
+++ b/MoinMoin/util/dataset.py	Sat Feb 24 16:48:08 2007 +0100
@@ -18,6 +18,7 @@
         ('sortable', 0),
         ('hidden', 0),
         ('align', ''),
+        ('autofilter', 0),
         ]
 
     def __init__(self, name, **kw):
@@ -42,10 +43,11 @@
     Note: Dataset rows and column must contain only ascii or Unicode values!  
     """
 
-    def __init__(self):
+    def __init__(self, data_id=None):
         self.columns = []
         self.data = []
         self._pos = 0
+        self.data_id = data_id
 
     def __len__(self):
         return len(self.data)
--- a/MoinMoin/widget/browser.py	Sat Feb 24 15:56:40 2007 +0100
+++ b/MoinMoin/widget/browser.py	Sat Feb 24 16:48:08 2007 +0100
@@ -7,53 +7,163 @@
 """
 
 from MoinMoin.widget import base
-
+from MoinMoin import wikiutil
 
 class DataBrowserWidget(base.Widget):
 
     def __init__(self, request, **kw):
+        _ = request.getText
         base.Widget.__init__(self, request, **kw)
         self.data = None
+        self.data_id = 'dbw.'
+        self._all = _('[all]')
+        self._notempty = _('[not empty]')
+        self._empty = _('[empty]')
+        self._filter = _('filter')
 
     def setData(self, dataset):
         """ Sets the data for the browser (see MoinMoin.util.dataset).
 
-        @param dataset: dataset containg either ascii or unicode
+        @param dataset: dataset containing either ascii, unicode or tuples.
+                        If a dataset entry contains a tuple then the first
+                        item in the tuple is displayed and the second item
+                        is used for autofilters.
         """
         self.data = dataset
+        if dataset.data_id:
+            self.data_id = 'dbw.%s.' % dataset.data_id
+
+    def _name(self, elem):
+        """ return name tag for a HTML element
+        @param elem: element name, will be prefixed by data id
+        """
+        return 'name="%s%s"' % (self.data_id, elem)
+
+    def _makeoption(self, item, selected):
+        """ create an option for a <select> form element
+        @param item: string containing the item name to show
+        @param selected: indicates whether the item should be default or not
+        """
+        if selected:
+            selected = ' selected'
+        else:
+            selected = ''
+        assert(isinstance(item, basestring))
+        item = wikiutil.escape(item)
+        return '<option value="%s"%s>%s</option>' % (item, selected, item)
+
+    def _filteroptions(self, idx):
+        """ create options for all elements in the column
+            given by idx
+        """
+        self.data.reset()
+        row = self.data.next()
+        # leave the 'empty' slot blank so we avoid adding
+        # blank items when getting all possibilities
+        unique = [self._all, '', self._notempty]
+
+        value = None
+        name = '%sfilter%d' % (self.data_id, idx)
+        if name in self.request.form:
+            value = self.request.form[name][0]
+        while row:
+            option = row[idx]
+            if isinstance(option, tuple):
+                option = option[1]
+            if not option in unique:
+                unique.append(option)
+            row = self.data.next()
+
+        # fill in the empty field we left blank
+        unique[1] = self._empty
+        return '\n'.join([self._makeoption(item, item == value) for item in unique])
 
     def format(self):
         fmt = self.request.formatter
 
         result = []
+        result.append(fmt.rawHTML('<form action="" method="GET">'))
+        result.append(fmt.div(1))
+
+        havefilters = False
+        for col in self.data.columns:
+            if col.autofilter:
+                havefilters = True
+                break
+        if havefilters:
+            result.append(fmt.rawHTML('<input type="submit" value="%s" %s>' % (self._filter, self._name('submit'))))
+
         result.append(fmt.table(1))
 
         # add header line
         result.append(fmt.table_row(1))
-        for col in self.data.columns:
+        for idx in range(len(self.data.columns)):
+            col = self.data.columns[idx]
             if col.hidden: continue
             result.append(fmt.table_cell(1))
             result.append(fmt.strong(1))
             result.append(col.label or col.name)
             result.append(fmt.strong(0))
+
+            if col.autofilter:
+                result.append(fmt.linebreak(False))
+                select = '<select %s>%s</select>' % (self._name('filter%d' % idx),
+                                                     self._filteroptions(idx))
+                result.append(fmt.rawHTML(select))
+
             result.append(fmt.table_cell(0))
         result.append(fmt.table_row(0))
 
         # add data
         self.data.reset()
         row = self.data.next()
-        while row:
-            result.append(fmt.table_row(1))
+        filters = [None] * len(row)
+
+        if havefilters:
             for idx in range(len(row)):
-                if self.data.columns[idx].hidden:
-                    continue
-                result.append(fmt.table_cell(1))
-                result.append(unicode(row[idx]))
-                result.append(fmt.table_cell(0))
-            result.append(fmt.table_row(0))
+                name = '%sfilter%d' % (self.data_id, idx)
+                if name in self.request.form:
+                    filters[idx] = self.request.form[name][0]
+                    if filters[idx] == self._all:
+                        filters[idx] = None
+
+        while row:
+            hidden = False
+
+            if havefilters:
+                # check if row needs to be hidden due to filtering
+                for idx in range(len(row)):
+                    if filters[idx]:
+                        if isinstance(row[idx], tuple):
+                            data = unicode(row[idx][1])
+                        else:
+                            data = unicode(row[idx])
+                        if data != '' and filters[idx] == self._notempty:
+                            continue
+                        if data == '' and filters[idx] == self._empty:
+                            continue
+                        if data != filters[idx]:
+                            hidden = True
+                            break
+
+            if not hidden:
+                result.append(fmt.table_row(1))
+                for idx in range(len(row)):
+                    if self.data.columns[idx].hidden:
+                        continue
+                    result.append(fmt.table_cell(1))
+                    if isinstance(row[idx], tuple):
+                        result.append(unicode(row[idx][0]))
+                    else:
+                        result.append(unicode(row[idx]))
+                    result.append(fmt.table_cell(0))
+                result.append(fmt.table_row(0))
+
             row = self.data.next()
 
         result.append(fmt.table(0))
+        result.append(fmt.div(0))
+        result.append(fmt.rawHTML('</form>'))
         return ''.join(result)
 
     toHTML = format # old name of "format" function DEPRECATED, will be removed in 1.7
--- a/docs/CHANGES	Sat Feb 24 15:56:40 2007 +0100
+++ b/docs/CHANGES	Sat Feb 24 16:48:08 2007 +0100
@@ -330,6 +330,8 @@
     * Make the FootNote macro filter duplicates and display a list of numbers
       instead of a list of identical footnotes. Thanks to Johannes Berg for the
       patch.
+    * autofilters for databrowser widget. Thanks to Johannes Berg for the patch.
+
 
   Bugfixes:
     * on action "info" page, "revert" link will not be displayed for empty page