[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