[Checkins] SVN: z3c.searchfilter/trunk/src/z3c/searchfilter/ Here is the code. No tests yet, since I refactored this code from a

Stephan Richter srichter at cosmos.phy.tufts.edu
Mon Feb 12 14:46:30 EST 2007


Log message for revision 72505:
  Here is the code. No tests yet, since I refactored this code from a 
  specific project. But tey will be there soon.
  
  

Changed:
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/README.txt
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/__init__.py
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/browser.py
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/criterium.py
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/criterium_row.pt
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/filter.pt
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/interfaces.py
  A   z3c.searchfilter/trunk/src/z3c/searchfilter/tests.py

-=-
Added: z3c.searchfilter/trunk/src/z3c/searchfilter/README.txt
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/README.txt	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/README.txt	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1,3 @@
+===============================
+Search Filters through Criteria
+===============================


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.searchfilter/trunk/src/z3c/searchfilter/__init__.py
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/__init__.py	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/__init__.py	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1 @@
+# Make a package


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.searchfilter/trunk/src/z3c/searchfilter/browser.py
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/browser.py	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/browser.py	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1,165 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Search Filter Browser View
+
+$Id$
+"""
+import persistent.dict
+import zope.component
+import zope.interface
+import zope.schema
+
+from hurry import query
+from z3c.searchfilter import interfaces
+from zope.app.form.browser import RadioWidget
+from zope.app.pagetemplate import ViewPageTemplateFile
+from zope.app.session.interfaces import ISession
+from zope.formlib import form
+from zope.index.text import parsetree
+from zope.location import location
+from zope.traversing import api
+
+from z3c.searchfilter import criterium
+from z3c.searchfilter.interfaces import _
+
+
+FILTER_KEY = 'z3c.searchfilter.filter'
+
+
+def ConnectorWidget(context, request):
+    return RadioWidget(context, context.vocabulary, request)
+
+class BaseCriteriumRow(form.SubPageForm):
+
+    template = ViewPageTemplateFile('criterium_row.pt')
+    actions = form.Actions()
+
+    def setUpWidgets(self, ignore_request=False):
+        self.adapters = {}
+        self.widgets = form.setUpEditWidgets(
+            self.form_fields, self.prefix, self.context, self.request,
+            adapters=self.adapters, ignore_request=ignore_request
+            )
+
+    def save(self):
+        data = {}
+        form.getWidgetsData(self.widgets, self.prefix, data)
+        form.applyChanges(self.context, self.form_fields, data, self.adapters)
+
+
+class FullTextCriteriumRow(BaseCriteriumRow):
+
+    form_fields = form.FormFields(
+        interfaces.IFullTextCriterium).select('value')
+
+
+class Filter(form.SubPageForm):
+
+    prefix = 'filters.'
+    form_fields = form.FormFields(interfaces.ISearchCriteria)
+    form_fields['connector'].custom_widget = ConnectorWidget
+
+    template = ViewPageTemplateFile('filter.pt')
+    criteriumRows = None
+
+    # Must be implemented by sub-class or instance
+    criteriaClass = None
+
+    # The filter name is used in the session to identify the type of filter
+    filterName = 'criteria'
+
+    # The context name is used in addition to the filter name to identify one
+    # filter for one specific context.
+    @property
+    def contextName(self):
+        return api.getName(self.context)
+
+    @property
+    def criteria(self):
+        session = ISession(self.request)
+        filters = session[FILTER_KEY]
+
+        filter = filters.get(self.filterName)
+        if filter is None:
+            # smells like we have to take care on references in this dict!
+            filters[self.filterName] = persistent.dict.PersistentDict()
+            filter = filters[self.filterName]
+
+        # Note, the context reference has to be deleted if we delete the
+        # context
+        criteria = filter.get(self.contextName)
+        if criteria is None:
+            criteria = filter[self.contextName] = self.criteriaClass()
+            # Locate the search criteria on the context, so that security does
+            # not get lost
+            location.locate(criteria, self.context, self.contextName)
+        return criteria
+
+    def values(self):
+        queries = []
+        # Generate the query
+        queries.append(self.criteria.generateQuery())
+        # Return the results
+        try:
+            return query.query.Query().searchResults(query.And(*queries))
+        except TypeError:
+            self.status = _('One of the criteria is setup improperly.')
+        except parsetree.ParseError, error:
+            self.status = _('Invalid search text.')
+        # Return an empty set, since an error must have occurred
+        return []
+
+    def available(self):
+        for name, factory in self.criteria.available():
+            yield {'name': name, 'title': factory.title}
+
+    def _createCriteriumRows(self):
+        self.criteriumRows = []
+        index = 0
+        for criterium in self.criteria:
+            row = zope.component.getMultiAdapter(
+                (criterium, self.request), name='row')
+            row.setPrefix(str(index))
+            row.update()
+            self.criteriumRows.append(row)
+            index += 1
+
+    def update(self):
+        # Make sure the criteria get updated
+        self._createCriteriumRows()
+        # Execute actions
+        super(Filter, self).update()
+
+    @form.action(_('Filter'))
+    def handleFilter(self, action, data):
+        if 'connector' in data:
+            self.criteria.connector = data['connector']
+        for row in self.criteriumRows:
+            row.save()
+
+    @form.action(_('Add'))
+    def handleAdd(self, action, data):
+        name = self.request.form[self.prefix + 'newCriterium']
+        self.criteria.add(name)
+        self._createCriteriumRows()
+        self.status = _('New criterium added.')
+
+    @form.action(_('Clear'))
+    def handleClear(self, action, data):
+        self.criteria.clear()
+        self._createCriteriumRows()
+        self.status = _('Criteria cleared.')
+
+    def render(self):
+        return self.template()


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/browser.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.searchfilter/trunk/src/z3c/searchfilter/criterium.py
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/criterium.py	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/criterium.py	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1,148 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Search Criteria Implementation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import hurry.query.value
+import hurry.query.set
+import persistent
+import persistent.list
+import zope.component
+import zope.interface
+from BTrees.IFBTree import IFBTree
+from hurry import query
+from zope.location import location
+from zope.schema.fieldproperty import FieldProperty
+
+from z3c.searchfilter import interfaces
+from z3c.searchfilter.interfaces import _
+
+class SearchCriteria(location.Location, persistent.list.PersistentList):
+    """Simple search criteria implementation.
+
+    This component uses the component architecture to determine its available
+    criterium components.
+    """
+    zope.interface.implements(interfaces.ISearchCriteria)
+
+    connector = FieldProperty(interfaces.ISearchCriteria['connector'])
+    # Must be implemented by sub-class or instance
+    allIndex = None
+
+    def clear(self):
+        """See interfaces.ISearchCriteria"""
+        super(SearchCriteria, self).__init__()
+        self.connector = query.Or
+
+    def add(self, name):
+        """See interfaces.ISearchCriteria"""
+        criterium = zope.component.getAdapter(
+            self, interfaces.ISearchCriteriumFactory, name=name)()
+        location.locate(criterium, self)
+        self.append(criterium)
+
+    def available(self):
+        """See interfaces.ISearchCriteria"""
+        adapters = zope.component.getAdapters(
+            (self,), interfaces.ISearchCriteriumFactory)
+        return sorted(adapters, key=lambda (n, a): a.weight)
+
+    def getAllQuery(self):
+        """See interfaces.ISearchCriteria"""
+        return hurry.query.value.ExtentAny(self.allIndex, None)
+
+    def generateQuery(self):
+        """See interfaces.ISearchCriteria"""
+        # If no criteria are selected, return all values
+        if not len(self):
+            return self.getAllQuery()
+        # Set up the queries of the contained criteria; if one setup fails,
+        # just ignore the criterium.
+        queries = []
+        for criterium in self:
+            try:
+                queries.append(criterium.generateQuery())
+            except AssertionError:
+                # The criterium is probably setup incorrectly
+                pass
+        # Match the specified criteria in comparison to all possible values.
+        return query.And(self.connector(*queries), self.getAllQuery())
+
+
+class SimpleSearchCriterium(persistent.Persistent):
+    """Search criterium for some data.
+
+    This search criterium is implemented as an adapter to the search
+    """
+    zope.interface.implements(interfaces.ISearchCriterium)
+
+    # See interfaces.ISearchCriterium
+    label = None
+    value = None
+    operator = query.value.Eq
+    operatorLabel = _('equals')
+    _index = None
+
+    def generateQuery(self):
+        """See interfaces.ISearchCriterium"""
+        return self.operator(self._index, self.value)
+
+
+class SimpleSetSearchCriterium(SimpleSearchCriterium):
+
+    operator = query.set.AnyOf
+    operatorLabel = _('is')
+
+    def generateQuery(self):
+        """See interfaces.ISearchCriterium"""
+        return self.operator(self._index, [self.value])
+
+
+class MatchFullText(query.Text):
+
+    def apply(self):
+        if not self.text:
+            return IFBTree()
+        return super(MatchFullText, self).apply()
+
+
+class FullTextCriterium(SimpleSearchCriterium):
+    """Search criterium for some data."""
+    zope.interface.implements(interfaces.IFullTextCriterium)
+
+    label = _('Text')
+    operator = MatchFullText
+    operatorLabel = _('matches')
+    value = FieldProperty(interfaces.IFullTextCriterium['value'])
+
+
+class SearchCriteriumFactoryBase(object):
+    """Search Criterium Factory."""
+    zope.interface.implements(interfaces.ISearchCriteriumFactory)
+
+    klass = None
+    title = None
+    weight = 0
+
+    def __init__(self, context):
+        pass
+
+    def __call__(self):
+        return self.klass()
+
+def factory(klass, title):
+    return type('%sFactory' %klass.__name__, (SearchCriteriumFactory,),
+                {'klass': klass, 'title': title})


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/criterium.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.searchfilter/trunk/src/z3c/searchfilter/criterium_row.pt
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/criterium_row.pt	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/criterium_row.pt	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1,13 @@
+<tr>
+  <td>
+    <span tal:content="context/label" i18n:translate="" />
+    <tal:block replace="structure view/widgets/object|nothing" />
+  </td>
+  <td width="50">
+    <tal:block replace="structure view/widgets/operator|nothing" />
+    <b tal:content="context/operatorLabel|nothing" i18n:translate="" />
+  </td>
+  <td>
+    <tal:block replace="structure view/widgets/value" />
+  </td>
+</tr>


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/criterium_row.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.searchfilter/trunk/src/z3c/searchfilter/filter.pt
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/filter.pt	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/filter.pt	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1,49 @@
+<fieldset>
+  <legend i18n:translate="">Filter</legend>
+
+  <div tal:condition="view/status"
+       tal:content="view/status">
+    Status
+  </div>
+
+  <form method="POST" action=""
+      tal:attributes="action request/URL">
+
+    <div>
+      <input tal:replace="structure view/widgets/connector" />
+    </div>
+    <div style="margin: 8px 0px">
+      <table width="950">
+        <tal:block
+            repeat="row view/criteriumRows"
+            replace="structure row/render" />
+      </table>
+    </div>
+    <div>
+      <label for=""
+             tal:attributes="for string:${view/prefix}newCriterium"
+             i18n:translate="">
+        New Criterium
+      </label>
+      <select name="" size="1"
+              tal:attributes="name string:${view/prefix}newCriterium">
+        <option value=""
+                tal:repeat="criterium view/available"
+                tal:attributes="value criterium/name"
+                tal:content="criterium/title">
+          Criterium Factory Title
+        </option>
+      </select>
+      <input tal:replace="structure
+          view/actions/filters.actions.add/render" />
+    </div>
+    <br />
+    <div>
+      <input tal:replace="structure
+          view/actions/filters.actions.filter/render" />
+      <input tal:replace="structure
+          view/actions/filters.actions.clear/render" />
+    </div>
+
+  </form>
+</fieldset>


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/filter.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.searchfilter/trunk/src/z3c/searchfilter/interfaces.py
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/interfaces.py	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/interfaces.py	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1,93 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Search Criteria Interfaces
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.i18nmessageid
+import zope.interface
+import zope.schema
+from hurry import query
+from zope.schema import vocabulary
+
+_ = zope.i18nmessageid.MessageFactory('z3c.searchfilter')
+
+
+class ISearchCriteria(zope.interface.Interface):
+    """Search criteria for position search."""
+
+    connector = zope.schema.Choice(
+        title=_('Connector'),
+        description=_('Criterium Connector'),
+        vocabulary=vocabulary.SimpleVocabulary((
+            vocabulary.SimpleTerm(query.Or, 'or',
+                                  _('Match any of the following')),
+            vocabulary.SimpleTerm(query.And, 'and',
+                                  _('Match all of the following'))
+            )),
+        default=query.Or,
+        required=True)
+
+    def clear():
+        """Clear the criteria."""
+
+    def add(criterium):
+        """Add a criterium."""
+
+    def available():
+        """Return a sequence of names of all available criteria."""
+
+    def getAllQuery(self):
+        """Get a query that returns all possible values."""
+
+    def generateQuery():
+        """Generate a query object."""
+
+
+class ISearchCriterium(zope.interface.Interface):
+    """A search citerium of a piece of data."""
+
+    label = zope.schema.TextLine(
+        title=_('Label'),
+        description=_('Label used to present the criterium.'),
+        required=True)
+
+    def generateQuery():
+        """Generate a query object."""
+
+
+class IFullTextCriterium(ISearchCriterium):
+
+    value = zope.schema.TextLine(
+        title=_('Search Query'),
+        required=True)
+
+
+class ISearchCriteriumFactory(zope.interface.Interface):
+    """A factory for the search criterium"""
+
+    title = zope.schema.TextLine(
+        title=_('Title'),
+        description=_('A human-readable title of the criterium.'),
+        required=True)
+
+    weight = zope.schema.Int(
+        title=_('Int'),
+        description=_('The weight/importance of the factory among all '
+                      'factories.'),
+        required=True)
+
+    def __call__():
+        """Generate the criterium."""


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/interfaces.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.searchfilter/trunk/src/z3c/searchfilter/tests.py
===================================================================
--- z3c.searchfilter/trunk/src/z3c/searchfilter/tests.py	2007-02-12 19:45:07 UTC (rev 72504)
+++ z3c.searchfilter/trunk/src/z3c/searchfilter/tests.py	2007-02-12 19:46:29 UTC (rev 72505)
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Search Filter Tests
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import unittest
+from zope.app.testing import setup
+from zope.testing import doctest
+from zope.testing.doctestunit import DocFileSuite
+from zope.testing.doctestunit import DocTestSuite
+from zope.testing.doctestunit import pprint
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('README.txt',
+                     setUp=setup.placefulSetUp,
+                     tearDown=setup.placefulTearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+


Property changes on: z3c.searchfilter/trunk/src/z3c/searchfilter/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id



More information about the Checkins mailing list