[Checkins] SVN: zope.app.catalog/tags/3.6.0/ Tag 3.6.0

Dan Korostelev nadako at gmail.com
Sat Jan 3 10:41:02 EST 2009


Log message for revision 94479:
  Tag 3.6.0

Changed:
  A   zope.app.catalog/tags/3.6.0/
  D   zope.app.catalog/tags/3.6.0/CHANGES.txt
  A   zope.app.catalog/tags/3.6.0/CHANGES.txt
  D   zope.app.catalog/tags/3.6.0/setup.py
  A   zope.app.catalog/tags/3.6.0/setup.py
  D   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/README.txt
  A   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/README.txt
  D   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/browser/configure.zcml
  A   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/browser/configure.zcml
  D   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/catalog.py
  A   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/catalog.py
  D   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/classes.zcml
  A   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/classes.zcml
  D   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/interfaces.py
  A   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/interfaces.py
  A   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/keyword.py
  D   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/text.py
  A   zope.app.catalog/tags/3.6.0/src/zope/app/catalog/text.py

-=-
Deleted: zope.app.catalog/tags/3.6.0/CHANGES.txt
===================================================================
--- zope.app.catalog/trunk/CHANGES.txt	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/CHANGES.txt	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,48 +0,0 @@
-=======
-CHANGES
-=======
-
-3.6.0 (unreleased)
-------------------
-
-- ...
-
-3.5.2 (2008-12-28)
-------------------
-
-- Remove testing dependencies from install_requires.
-
-3.5.1 (2007-10-31)
-------------------
-
-- Resolve ``ZopeSecurityPolicy`` deprecation warning.
-
-
-3.5.0 (2007-10-11)
-------------------
-
-- Updated some meta-data.
-
-- Move ``ftests.py`` to ``tests.py``.
-
-
-3.5.0a3 (2007-09-27)
---------------------
-
-- removed some deprecations
-
-
-3.5.0a2 (2007-09-21)
---------------------
-
-- bugfix: passing the context to getAllUtilitiesRegisteredFor in all
-  eventhandlers because no catalog was found which was located in a
-  sub site and for example the ObjectModifiesEvent get fired from somewhere
-  in the root.
-
-
-3.5.0a1 (2007-06-26)
---------------------
-
-- Added marker interfaces to prevent automatic indexing (see: ``event.txt``)
-

Copied: zope.app.catalog/tags/3.6.0/CHANGES.txt (from rev 94477, zope.app.catalog/trunk/CHANGES.txt)
===================================================================
--- zope.app.catalog/tags/3.6.0/CHANGES.txt	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/CHANGES.txt	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,59 @@
+=======
+CHANGES
+=======
+
+3.6.0 (2009-01-03)
+------------------
+
+- Make TextIndex addform use default values as specified in
+  zope.app.catalog.text.ITextIndex interface. Also, change
+  "searchableText" to "getSearchableText" there, as it's the
+  right value.
+
+- Add Keyword (case-insensitive and case-sensitive) catalog
+  indices. It's now possible to use them, because ones in
+  zope.index now implement IIndexSearch interface.
+
+- Add support for sorting, reversing and limiting result set
+  in the ``searchResults`` method, using new IIndexSort interface
+  features of zope.index.
+
+3.5.2 (2008-12-28)
+------------------
+
+- Remove testing dependencies from install_requires.
+
+3.5.1 (2007-10-31)
+------------------
+
+- Resolve ``ZopeSecurityPolicy`` deprecation warning.
+
+
+3.5.0 (2007-10-11)
+------------------
+
+- Updated some meta-data.
+
+- Move ``ftests.py`` to ``tests.py``.
+
+
+3.5.0a3 (2007-09-27)
+--------------------
+
+- removed some deprecations
+
+
+3.5.0a2 (2007-09-21)
+--------------------
+
+- bugfix: passing the context to getAllUtilitiesRegisteredFor in all
+  eventhandlers because no catalog was found which was located in a
+  sub site and for example the ObjectModifiesEvent get fired from somewhere
+  in the root.
+
+
+3.5.0a1 (2007-06-26)
+--------------------
+
+- Added marker interfaces to prevent automatic indexing (see: ``event.txt``)
+

Deleted: zope.app.catalog/tags/3.6.0/setup.py
===================================================================
--- zope.app.catalog/trunk/setup.py	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/setup.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,81 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation 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.
-#
-##############################################################################
-"""Setup for zope.app.catalog package
-
-$Id$
-"""
-import os
-from setuptools import setup, find_packages
-
-def read(*rnames):
-    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
-
-setup(name = 'zope.app.catalog',
-      version = '3.6.0dev',
-      author='Zope Corporation and Contributors',
-      author_email='zope3-dev at zope.org',
-      description='Zope Cataloging and Indexing Framework',
-      long_description=(
-          read('README.txt')
-          + '\n\n' +
-          'Detailed Documentation\n'
-          '**********************\n'
-          + '\n\n' +
-          read('src', 'zope', 'app', 'catalog', 'README.txt')
-          + '\n\n' +
-          read('src', 'zope', 'app', 'catalog', 'event.txt')
-          + '\n\n' +
-          read('CHANGES.txt')
-          ),
-      keywords = "zope3 catalog index",
-      classifiers = [
-          'Development Status :: 5 - Production/Stable',
-          'Environment :: Web Environment',
-          'Intended Audience :: Developers',
-          'License :: OSI Approved :: Zope Public License',
-          'Programming Language :: Python',
-          'Natural Language :: English',
-          'Operating System :: OS Independent',
-          'Topic :: Internet :: WWW/HTTP',
-          'Framework :: Zope3'],
-      url='http://cheeseshop.python.org/pypi/zope.app.catalog',
-      license='ZPL 2.1',
-      packages=find_packages('src'),
-      package_dir = {'': 'src'},
-      namespace_packages=['zope', 'zope.app'],
-      extras_require = dict(
-          test=['zope.testing',
-                'zope.app.component',
-                'zope.app.testing',
-                'zope.app.securitypolicy',
-                'zope.app.zcmlfiles',
-                'zope.app.zptpage',
-                ]),
-      install_requires = [
-          'setuptools',
-          'ZODB3',
-          'zope.annotation',
-          'zope.app.container',
-          'zope.app.intid',
-          'zope.component',
-          'zope.index',
-          'zope.interface',
-          'zope.lifecycleevent',
-          'zope.location',
-          'zope.schema',
-          'zope.traversing',
-          ],
-      include_package_data = True,
-      zip_safe = False,
-      )

Copied: zope.app.catalog/tags/3.6.0/setup.py (from rev 94477, zope.app.catalog/trunk/setup.py)
===================================================================
--- zope.app.catalog/tags/3.6.0/setup.py	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/setup.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,81 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation 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.
+#
+##############################################################################
+"""Setup for zope.app.catalog package
+
+$Id$
+"""
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(name = 'zope.app.catalog',
+      version = '3.6.0',
+      author='Zope Corporation and Contributors',
+      author_email='zope-dev at zope.org',
+      description='Zope Cataloging and Indexing Framework',
+      long_description=(
+          read('README.txt')
+          + '\n\n' +
+          'Detailed Documentation\n'
+          '**********************\n'
+          + '\n\n' +
+          read('src', 'zope', 'app', 'catalog', 'README.txt')
+          + '\n\n' +
+          read('src', 'zope', 'app', 'catalog', 'event.txt')
+          + '\n\n' +
+          read('CHANGES.txt')
+          ),
+      keywords = "zope3 catalog index",
+      classifiers = [
+          'Development Status :: 5 - Production/Stable',
+          'Environment :: Web Environment',
+          'Intended Audience :: Developers',
+          'License :: OSI Approved :: Zope Public License',
+          'Programming Language :: Python',
+          'Natural Language :: English',
+          'Operating System :: OS Independent',
+          'Topic :: Internet :: WWW/HTTP',
+          'Framework :: Zope3'],
+      url='http://pypi.python.org/pypi/zope.app.catalog',
+      license='ZPL 2.1',
+      packages=find_packages('src'),
+      package_dir = {'': 'src'},
+      namespace_packages=['zope', 'zope.app'],
+      extras_require = dict(
+          test=['zope.testing',
+                'zope.app.component',
+                'zope.app.testing',
+                'zope.app.securitypolicy',
+                'zope.app.zcmlfiles',
+                'zope.app.zptpage',
+                ]),
+      install_requires = [
+          'setuptools',
+          'ZODB3',
+          'zope.annotation',
+          'zope.app.container',
+          'zope.app.intid',
+          'zope.component',
+          'zope.index>=3.5.0',
+          'zope.interface',
+          'zope.lifecycleevent',
+          'zope.location',
+          'zope.schema',
+          'zope.traversing',
+          ],
+      include_package_data = True,
+      zip_safe = False,
+      )

Deleted: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/README.txt
===================================================================
--- zope.app.catalog/trunk/src/zope/app/catalog/README.txt	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/README.txt	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,305 +0,0 @@
-Catalogs
-========
-
-Catalogs provide management of collections of related indexes with a
-basic search algorithm.  Let's look at an example:
-
-    >>> from zope.app.catalog.catalog import Catalog
-    >>> cat = Catalog()
-
-We can add catalog indexes to catalogs.  A catalog index is, among
-other things, an attribute index. It indexes attributes of objects. To
-see how this works, we'll create a demonstration attribute index. Our
-attribute index will simply keep track of objects that have a given
-attribute value.  The `catalog` package provides an attribute-index
-mix-in class that is meant to work with a base indexing class. First,
-we'll write the base index class:
-
-    >>> import persistent, BTrees.OOBTree, BTrees.IFBTree, BTrees.IOBTree
-    >>> import zope.interface, zope.index.interfaces
-
-    >>> class BaseIndex(persistent.Persistent):
-    ...     zope.interface.implements(
-    ...         zope.index.interfaces.IInjection,
-    ...         zope.index.interfaces.IIndexSearch,
-    ...         )
-    ...
-    ...     def clear(self):
-    ...         self.forward = BTrees.OOBTree.OOBTree()
-    ...         self.backward = BTrees.IOBTree.IOBTree()
-    ...
-    ...     __init__ = clear
-    ...
-    ...     def index_doc(self, docid, value):
-    ...         if docid in self.backward:
-    ...             self.unindex_doc(docid)
-    ...         self.backward[docid] = value
-    ...
-    ...         set = self.forward.get(value)
-    ...         if set is None:
-    ...             set = BTrees.IFBTree.IFTreeSet()
-    ...             self.forward[value] = set
-    ...         set.insert(docid)
-    ...
-    ...     def unindex_doc(self, docid):
-    ...         value = self.backward.get(docid)
-    ...         if value is None:
-    ...             return
-    ...         self.forward[value].remove(docid)
-    ...         del self.backward[docid]
-    ...
-    ...     def apply(self, value):
-    ...         set = self.forward.get(value)
-    ...         if set is None:
-    ...             set = BTrees.IFBTree.IFTreeSet()
-    ...         return set
-
-The class implements `IInjection` to allow values to be indexed and
-unindexed and `IIndexSearch` to support searching via the `apply`
-method.
-
-Now, we can use the AttributeIndex mixin to make this an attribute
-index:
-
-    >>> import zope.app.catalog.attribute
-    >>> import zope.app.container.contained
-    >>> import zope.app.catalog.interfaces
-
-    >>> class Index(zope.app.catalog.attribute.AttributeIndex, 
-    ...             BaseIndex,
-    ...             zope.app.container.contained.Contained,
-    ...             ):
-    ...    zope.interface.implements(zope.app.catalog.interfaces.ICatalogIndex)
-
-Unfortunately, because of the way we currently handle containment
-constraints, we have to provide `ICatalogIndex`, which extends
-`IContained`. We subclass `Contained` to get an implementation for
-`IContained`. 
-
-Now let's add some of these indexes to our catalog.  Let's create some
-indexes.  First we'll define some interfaces providing data to index:
-
-    >>> class IFavoriteColor(zope.interface.Interface):
-    ...     color = zope.interface.Attribute("Favorite color")
-
-    >>> class IPerson(zope.interface.Interface):
-    ...     def age():
-    ...         """Return the person's age, in years"""
-
-We'll create color and age indexes:
-
-    >>> cat['color'] = Index('color', IFavoriteColor)
-    >>> cat['age'] = Index('age', IPerson, True)
-    >>> cat['size'] = Index('sz')
-
-The indexes are created with:
-
-- the name of the of the attribute to index
-
-- the interface defining the attribute, and
-
-- a flag indicating whether the attribute should be called, which
-  defaults to false.
-
-If an interface is provided, then we'll only be able to index an
-object if it can be adapted to the interface, otherwise, we'll simply
-try to get the attribute from the object. If the attribute isn't
-present, then we'll ignore the object.
-
-Now, let's create some objects and index them:
-
-    >>> class Person:
-    ...     zope.interface.implements(IPerson)
-    ...     def __init__(self, age):
-    ...         self._age = age
-    ...     def age(self):
-    ...         return self._age
-
-    >>> class Discriminating:
-    ...     zope.interface.implements(IFavoriteColor)
-    ...     def __init__(self, color):
-    ...         self.color = color
-
-    >>> class DiscriminatingPerson(Discriminating, Person):
-    ...     def __init__(self, age, color):
-    ...         Discriminating.__init__(self, color)
-    ...         Person.__init__(self, age)
-
-    >>> class Whatever:
-    ...     def __init__(self, **kw):
-    ...         self.__dict__.update(kw)
-
-    >>> o1 = Person(10)
-    >>> o2 = DiscriminatingPerson(20, 'red')
-    >>> o3 = Discriminating('blue')
-    >>> o4 = Whatever(a=10, c='blue', sz=5)
-    >>> o5 = Whatever(a=20, c='red', sz=6)
-    >>> o6 = DiscriminatingPerson(10, 'blue')
-
-    >>> cat.index_doc(1, o1)
-    >>> cat.index_doc(2, o2)
-    >>> cat.index_doc(3, o3)
-    >>> cat.index_doc(4, o4)
-    >>> cat.index_doc(5, o5)
-    >>> cat.index_doc(6, o6)
-
-We search by providing query mapping objects that have a key for every
-index we want to use:
-
-    >>> list(cat.apply({'age': 10}))
-    [1, 6]
-    >>> list(cat.apply({'age': 10, 'color': 'blue'}))
-    [6]
-    >>> list(cat.apply({'age': 10, 'color': 'blue', 'size': 5}))
-    []
-    >>> list(cat.apply({'size': 5}))
-    [4]
-
-We can unindex objects:
-
-    >>> cat.unindex_doc(4)
-    >>> list(cat.apply({'size': 5}))
-    []
-
-and reindex objects:
-
-    >>> o5.sz = 5
-    >>> cat.index_doc(5, o5)
-    >>> list(cat.apply({'size': 5}))
-    [5]
-
-If we clear the catalog, we'll clear all of the indexes:
-
-    >>> cat.clear()
-    >>> [len(index.forward) for index in cat.values()]
-    [0, 0, 0]
-
-Note that you don't have to use the catalog's search methods. You can
-access its indexes directly, since the catalog is a mapping:
-
-    >>> [(name, cat[name].field_name) for name in cat]
-    [(u'age', 'age'), (u'color', 'color'), (u'size', 'sz')]
-
-Catalogs work with int-id utilities, which are responsible for
-maintaining id <-> object mappings.  To see how this works, we'll
-create a utility to work with our catalog:
-
-    >>> import zope.app.intid.interfaces
-    >>> class Ids:
-    ...     zope.interface.implements(zope.app.intid.interfaces.IIntIds)
-    ...     def __init__(self, data):
-    ...         self.data = data
-    ...     def getObject(self, id):
-    ...         return self.data[id]
-    ...     def __iter__(self):
-    ...         return self.data.iterkeys()
-    >>> ids = Ids({1: o1, 2: o2, 3: o3, 4: o4, 5: o5, 6: o6})
-    
-    >>> from zope.app.testing import ztapi
-    >>> ztapi.provideUtility(zope.app.intid.interfaces.IIntIds, ids)
-
-With this utility in place, catalogs can recompute indexes:
-
-    >>> cat.updateIndex(cat['size'])
-    >>> list(cat.apply({'size': 5}))
-    [4, 5]
-
-Of course, that only updates *that* index:
-
-    >>> list(cat.apply({'age': 10}))
-    []
-
-We can update all of the indexes:
-
-    >>> cat.updateIndexes()
-    >>> list(cat.apply({'age': 10}))
-    [1, 6]
-    >>> list(cat.apply({'color': 'red'}))
-    [2]
-    
-
-There's an alternate search interface that returns "result sets".
-Result sets provide access to objects, rather than object ids:
-
-    >>> result = cat.searchResults(size=5)
-    >>> len(result)
-    2
-    >>> list(result) == [o4, o5]
-    True
-
-The index example we looked at didn't provide document scores.  Simple
-indexes normally don't, but more complex indexes might give results
-scores, according to how closely a document matches a query.  Let's
-create a new index, a "keyword index" that indexes sequences of
-values:
-
-    >>> class BaseKeywordIndex(persistent.Persistent):
-    ...     zope.interface.implements(
-    ...         zope.index.interfaces.IInjection,
-    ...         zope.index.interfaces.IIndexSearch,
-    ...         )
-    ...
-    ...     def clear(self):
-    ...         self.forward = BTrees.OOBTree.OOBTree()
-    ...         self.backward = BTrees.IOBTree.IOBTree()
-    ...
-    ...     __init__ = clear
-    ...
-    ...     def index_doc(self, docid, values):
-    ...         if docid in self.backward:
-    ...             self.unindex_doc(docid)
-    ...         self.backward[docid] = values
-    ...
-    ...         for value in values:
-    ...             set = self.forward.get(value)
-    ...             if set is None:
-    ...                 set = BTrees.IFBTree.IFTreeSet()
-    ...                 self.forward[value] = set
-    ...             set.insert(docid)
-    ...
-    ...     def unindex_doc(self, docid):
-    ...         values = self.backward.get(docid)
-    ...         if values is None:
-    ...             return
-    ...         for value in values:
-    ...             self.forward[value].remove(docid)
-    ...         del self.backward[docid]
-    ...
-    ...     def apply(self, values):
-    ...         result = BTrees.IFBTree.IFBucket()
-    ...         for value in values:
-    ...             set = self.forward.get(value)
-    ...             if set is not None:
-    ...                 _, result = BTrees.IFBTree.weightedUnion(result, set)
-    ...         return result
-
-    >>> class KeywordIndex(zope.app.catalog.attribute.AttributeIndex, 
-    ...                    BaseKeywordIndex,
-    ...                    zope.app.container.contained.Contained,
-    ...                    ):
-    ...    zope.interface.implements(zope.app.catalog.interfaces.ICatalogIndex)
-
-Now, we'll add a hobbies index:
-
-    >>> cat['hobbies'] = KeywordIndex('hobbies')
-    >>> o1.hobbies = 'camping', 'music'
-    >>> o2.hobbies = 'hacking', 'sailing'
-    >>> o3.hobbies = 'music', 'camping', 'sailing'
-    >>> o6.hobbies = 'cooking', 'dancing'
-    >>> cat.updateIndexes()
-
-When we apply the catalog:
-
-    >>> cat.apply({'hobbies': ['music', 'camping', 'sailing']})
-    BTrees.IFBTree.IFBucket([(1, 2.0), (2, 1.0), (3, 3.0)])
-
-We found objects 1-3, because they each contained at least some of the
-words in the query.  The scores represent the number of words that
-matched. If we also include age:
-
-    >>> cat.apply({'hobbies': ['music', 'camping', 'sailing'], 'age': 10})
-    BTrees.IFBTree.IFBucket([(1, 3.0)])
-
-The score increased because we used an additional index.  If an index
-doesn't provide scores, scores of 1.0 are assumed.
-

Copied: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/README.txt (from rev 94477, zope.app.catalog/trunk/src/zope/app/catalog/README.txt)
===================================================================
--- zope.app.catalog/tags/3.6.0/src/zope/app/catalog/README.txt	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/README.txt	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,360 @@
+Catalogs
+========
+
+Catalogs provide management of collections of related indexes with a
+basic search algorithm.  Let's look at an example:
+
+    >>> from zope.app.catalog.catalog import Catalog
+    >>> cat = Catalog()
+
+We can add catalog indexes to catalogs.  A catalog index is, among
+other things, an attribute index. It indexes attributes of objects. To
+see how this works, we'll create a demonstration attribute index. Our
+attribute index will simply keep track of objects that have a given
+attribute value.  The `catalog` package provides an attribute-index
+mix-in class that is meant to work with a base indexing class. First,
+we'll write the base index class:
+
+    >>> import persistent, BTrees.OOBTree, BTrees.IFBTree, BTrees.IOBTree
+    >>> import zope.interface, zope.index.interfaces
+
+    >>> class BaseIndex(persistent.Persistent):
+    ...     zope.interface.implements(
+    ...         zope.index.interfaces.IInjection,
+    ...         zope.index.interfaces.IIndexSearch,
+    ...         zope.index.interfaces.IIndexSort,
+    ...         )
+    ...
+    ...     def clear(self):
+    ...         self.forward = BTrees.OOBTree.OOBTree()
+    ...         self.backward = BTrees.IOBTree.IOBTree()
+    ...
+    ...     __init__ = clear
+    ...
+    ...     def index_doc(self, docid, value):
+    ...         if docid in self.backward:
+    ...             self.unindex_doc(docid)
+    ...         self.backward[docid] = value
+    ...
+    ...         set = self.forward.get(value)
+    ...         if set is None:
+    ...             set = BTrees.IFBTree.IFTreeSet()
+    ...             self.forward[value] = set
+    ...         set.insert(docid)
+    ...
+    ...     def unindex_doc(self, docid):
+    ...         value = self.backward.get(docid)
+    ...         if value is None:
+    ...             return
+    ...         self.forward[value].remove(docid)
+    ...         del self.backward[docid]
+    ...
+    ...     def apply(self, value):
+    ...         set = self.forward.get(value)
+    ...         if set is None:
+    ...             set = BTrees.IFBTree.IFTreeSet()
+    ...         return set
+    ...
+    ...     def sort(self, docids, limit=None, reverse=False):
+    ...         for i, docid in enumerate(sorted(docids, key=self.backward.get, reverse=reverse)):
+    ...             yield docid
+    ...             if limit and i >= (limit - 1):
+    ...                 break
+
+The class implements `IInjection` to allow values to be indexed and
+unindexed and `IIndexSearch` to support searching via the `apply`
+method.
+
+Now, we can use the AttributeIndex mixin to make this an attribute
+index:
+
+    >>> import zope.app.catalog.attribute
+    >>> import zope.app.container.contained
+    >>> import zope.app.catalog.interfaces
+
+    >>> class Index(zope.app.catalog.attribute.AttributeIndex, 
+    ...             BaseIndex,
+    ...             zope.app.container.contained.Contained,
+    ...             ):
+    ...    zope.interface.implements(zope.app.catalog.interfaces.ICatalogIndex)
+
+Unfortunately, because of the way we currently handle containment
+constraints, we have to provide `ICatalogIndex`, which extends
+`IContained`. We subclass `Contained` to get an implementation for
+`IContained`. 
+
+Now let's add some of these indexes to our catalog.  Let's create some
+indexes.  First we'll define some interfaces providing data to index:
+
+    >>> class IFavoriteColor(zope.interface.Interface):
+    ...     color = zope.interface.Attribute("Favorite color")
+
+    >>> class IPerson(zope.interface.Interface):
+    ...     def age():
+    ...         """Return the person's age, in years"""
+
+We'll create color and age indexes:
+
+    >>> cat['color'] = Index('color', IFavoriteColor)
+    >>> cat['age'] = Index('age', IPerson, True)
+    >>> cat['size'] = Index('sz')
+
+The indexes are created with:
+
+- the name of the of the attribute to index
+
+- the interface defining the attribute, and
+
+- a flag indicating whether the attribute should be called, which
+  defaults to false.
+
+If an interface is provided, then we'll only be able to index an
+object if it can be adapted to the interface, otherwise, we'll simply
+try to get the attribute from the object. If the attribute isn't
+present, then we'll ignore the object.
+
+Now, let's create some objects and index them:
+
+    >>> class Person:
+    ...     zope.interface.implements(IPerson)
+    ...     def __init__(self, age):
+    ...         self._age = age
+    ...     def age(self):
+    ...         return self._age
+
+    >>> class Discriminating:
+    ...     zope.interface.implements(IFavoriteColor)
+    ...     def __init__(self, color):
+    ...         self.color = color
+
+    >>> class DiscriminatingPerson(Discriminating, Person):
+    ...     def __init__(self, age, color):
+    ...         Discriminating.__init__(self, color)
+    ...         Person.__init__(self, age)
+
+    >>> class Whatever:
+    ...     def __init__(self, **kw):
+    ...         self.__dict__.update(kw)
+
+    >>> o1 = Person(10)
+    >>> o2 = DiscriminatingPerson(20, 'red')
+    >>> o3 = Discriminating('blue')
+    >>> o4 = Whatever(a=10, c='blue', sz=5)
+    >>> o5 = Whatever(a=20, c='red', sz=6)
+    >>> o6 = DiscriminatingPerson(10, 'blue')
+
+    >>> cat.index_doc(1, o1)
+    >>> cat.index_doc(2, o2)
+    >>> cat.index_doc(3, o3)
+    >>> cat.index_doc(4, o4)
+    >>> cat.index_doc(5, o5)
+    >>> cat.index_doc(6, o6)
+
+We search by providing query mapping objects that have a key for every
+index we want to use:
+
+    >>> list(cat.apply({'age': 10}))
+    [1, 6]
+    >>> list(cat.apply({'age': 10, 'color': 'blue'}))
+    [6]
+    >>> list(cat.apply({'age': 10, 'color': 'blue', 'size': 5}))
+    []
+    >>> list(cat.apply({'size': 5}))
+    [4]
+
+We can unindex objects:
+
+    >>> cat.unindex_doc(4)
+    >>> list(cat.apply({'size': 5}))
+    []
+
+and reindex objects:
+
+    >>> o5.sz = 5
+    >>> cat.index_doc(5, o5)
+    >>> list(cat.apply({'size': 5}))
+    [5]
+
+If we clear the catalog, we'll clear all of the indexes:
+
+    >>> cat.clear()
+    >>> [len(index.forward) for index in cat.values()]
+    [0, 0, 0]
+
+Note that you don't have to use the catalog's search methods. You can
+access its indexes directly, since the catalog is a mapping:
+
+    >>> [(name, cat[name].field_name) for name in cat]
+    [(u'age', 'age'), (u'color', 'color'), (u'size', 'sz')]
+
+Catalogs work with int-id utilities, which are responsible for
+maintaining id <-> object mappings.  To see how this works, we'll
+create a utility to work with our catalog:
+
+    >>> import zope.app.intid.interfaces
+    >>> class Ids:
+    ...     zope.interface.implements(zope.app.intid.interfaces.IIntIds)
+    ...     def __init__(self, data):
+    ...         self.data = data
+    ...     def getObject(self, id):
+    ...         return self.data[id]
+    ...     def __iter__(self):
+    ...         return self.data.iterkeys()
+    >>> ids = Ids({1: o1, 2: o2, 3: o3, 4: o4, 5: o5, 6: o6})
+    
+    >>> from zope.app.testing import ztapi
+    >>> ztapi.provideUtility(zope.app.intid.interfaces.IIntIds, ids)
+
+With this utility in place, catalogs can recompute indexes:
+
+    >>> cat.updateIndex(cat['size'])
+    >>> list(cat.apply({'size': 5}))
+    [4, 5]
+
+Of course, that only updates *that* index:
+
+    >>> list(cat.apply({'age': 10}))
+    []
+
+We can update all of the indexes:
+
+    >>> cat.updateIndexes()
+    >>> list(cat.apply({'age': 10}))
+    [1, 6]
+    >>> list(cat.apply({'color': 'red'}))
+    [2]
+    
+
+There's an alternate search interface that returns "result sets".
+Result sets provide access to objects, rather than object ids:
+
+    >>> result = cat.searchResults(size=5)
+    >>> len(result)
+    2
+    >>> list(result) == [o4, o5]
+    True
+
+The searchResults method also provides a way to sort, limit and reverse
+results.
+
+When not using sorting, limiting and reversing are done by simple slicing
+and list reversing.
+
+    >>> list(cat.searchResults(size=5, _reverse=True)) == [o5, o4]
+    True
+
+    >>> list(cat.searchResults(size=5, _limit=1)) == [o4]
+    True
+
+    >>> list(cat.searchResults(size=5, _limit=1, _reverse=True)) == [o5]
+    True
+
+However, when using sorting by index, the limit and reverse parameters
+are passed to the index ``sort`` method so it can do it efficiently.
+
+Let's index more objects to work with:
+
+    >>> o7 = DiscriminatingPerson(7, 'blue')
+    >>> o8 = DiscriminatingPerson(3, 'blue')
+    >>> o9 = DiscriminatingPerson(14, 'blue')
+    >>> o10 = DiscriminatingPerson(1, 'blue')
+    >>> ids.data.update({7: o7, 8: o8, 9: o9, 10: o10})
+    >>> cat.index_doc(7, o7)
+    >>> cat.index_doc(8, o8)
+    >>> cat.index_doc(9, o9)
+    >>> cat.index_doc(10, o10)
+
+Now we can search all people who like blue, ordered by age:
+
+    >>> results = list(cat.searchResults(color='blue', _sort_index='age'))
+    >>> results == [o3, o10, o8, o7, o6, o9]
+    True
+
+    >>> results = list(cat.searchResults(color='blue', _sort_index='age', _limit=3))
+    >>> results == [o3, o10, o8]
+    True
+
+    >>> results = list(cat.searchResults(color='blue', _sort_index='age', _reverse=True))
+    >>> results == [o9, o6, o7, o8, o10, o3]
+    True
+
+    >>> results = list(cat.searchResults(color='blue', _sort_index='age', _reverse=True, _limit=4))
+    >>> results == [o9, o6, o7, o8]
+    True
+
+The index example we looked at didn't provide document scores.  Simple
+indexes normally don't, but more complex indexes might give results
+scores, according to how closely a document matches a query.  Let's
+create a new index, a "keyword index" that indexes sequences of
+values:
+
+    >>> class BaseKeywordIndex(persistent.Persistent):
+    ...     zope.interface.implements(
+    ...         zope.index.interfaces.IInjection,
+    ...         zope.index.interfaces.IIndexSearch,
+    ...         )
+    ...
+    ...     def clear(self):
+    ...         self.forward = BTrees.OOBTree.OOBTree()
+    ...         self.backward = BTrees.IOBTree.IOBTree()
+    ...
+    ...     __init__ = clear
+    ...
+    ...     def index_doc(self, docid, values):
+    ...         if docid in self.backward:
+    ...             self.unindex_doc(docid)
+    ...         self.backward[docid] = values
+    ...
+    ...         for value in values:
+    ...             set = self.forward.get(value)
+    ...             if set is None:
+    ...                 set = BTrees.IFBTree.IFTreeSet()
+    ...                 self.forward[value] = set
+    ...             set.insert(docid)
+    ...
+    ...     def unindex_doc(self, docid):
+    ...         values = self.backward.get(docid)
+    ...         if values is None:
+    ...             return
+    ...         for value in values:
+    ...             self.forward[value].remove(docid)
+    ...         del self.backward[docid]
+    ...
+    ...     def apply(self, values):
+    ...         result = BTrees.IFBTree.IFBucket()
+    ...         for value in values:
+    ...             set = self.forward.get(value)
+    ...             if set is not None:
+    ...                 _, result = BTrees.IFBTree.weightedUnion(result, set)
+    ...         return result
+
+    >>> class KeywordIndex(zope.app.catalog.attribute.AttributeIndex, 
+    ...                    BaseKeywordIndex,
+    ...                    zope.app.container.contained.Contained,
+    ...                    ):
+    ...    zope.interface.implements(zope.app.catalog.interfaces.ICatalogIndex)
+
+Now, we'll add a hobbies index:
+
+    >>> cat['hobbies'] = KeywordIndex('hobbies')
+    >>> o1.hobbies = 'camping', 'music'
+    >>> o2.hobbies = 'hacking', 'sailing'
+    >>> o3.hobbies = 'music', 'camping', 'sailing'
+    >>> o6.hobbies = 'cooking', 'dancing'
+    >>> cat.updateIndexes()
+
+When we apply the catalog:
+
+    >>> cat.apply({'hobbies': ['music', 'camping', 'sailing']})
+    BTrees.IFBTree.IFBucket([(1, 2.0), (2, 1.0), (3, 3.0)])
+
+We found objects 1-3, because they each contained at least some of the
+words in the query.  The scores represent the number of words that
+matched. If we also include age:
+
+    >>> cat.apply({'hobbies': ['music', 'camping', 'sailing'], 'age': 10})
+    BTrees.IFBTree.IFBucket([(1, 3.0)])
+
+The score increased because we used an additional index.  If an index
+doesn't provide scores, scores of 1.0 are assumed.
+

Deleted: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/browser/configure.zcml
===================================================================
--- zope.app.catalog/trunk/src/zope/app/catalog/browser/configure.zcml	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/browser/configure.zcml	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,95 +0,0 @@
-<zope:configure
-   xmlns:zope="http://namespaces.zope.org/zope"
-   xmlns="http://namespaces.zope.org/browser"
-   i18n_domain="zope"
-   >
-
-<!-- Allow a catalog to be added to content space -->
-<addMenuItem
-    title="Catalog"
-    description="A Catalog allows indexing and searching of objects"
-    class="zope.app.catalog.catalog.Catalog"
-    permission="zope.ManageContent"
-    />
-
-<icon
-    name="zmi_icon"
-    for="zope.app.catalog.interfaces.ICatalog"
-    file="catalog_icon.gif"
-    />
-
-<containerViews
-     for="..interfaces.ICatalog"
-     contents="zope.ManageServices"
-     index="zope.ManageServices"
-     add="zope.ManageServices"
-     />
-
-<pages
-    for="..interfaces.ICatalog"
-    class=".catalog.Advanced"
-    permission="zope.ManageContent">
-
-  <page name="advanced.html" template="advanced.pt"
-        menu="zmi_views" title="Advanced"/>
-  <page name="reindex.html" attribute="reindex"/>
-</pages>
-
-<!-- Indexes -->
-
-<addform
-    name="AddFieldIndex"
-    label="Add a field index"
-    schema="..interfaces.IAttributeIndex"
-    permission="zope.ManageServices"
-    content_factory="..field.FieldIndex"
-    arguments="field_name"
-    keyword_arguments="interface field_callable"
-    />
-
-<addMenuItem
-    title="Field Index"
-    description="Index items based on an orderable field value"
-    class="..field.FieldIndex"
-    permission="zope.ManageServices"
-    view="AddFieldIndex"
-   />
-
-<schemadisplay
-    name="index.html"
-    schema="..field.IFieldIndex"
-    label="Field Index"
-    fields="interface field_name field_callable"
-    permission="zope.ManageServices"
-    menu="zmi_views" title="Configuration"
-    />
-
-<addform
-    name="AddTextIndex"
-    label="Add a text index"
-    schema="..interfaces.IAttributeIndex"
-    permission="zope.ManageServices"
-    content_factory="..text.TextIndex"
-    arguments="field_name"
-    keyword_arguments="interface field_callable"
-    />
-
-<addMenuItem
-    title="Text Index"
-    description="Index items based on multi-value fields with
-                 orderable values"
-    class="..text.TextIndex"
-    permission="zope.ManageServices"
-    view="AddTextIndex"
-   />
-
-<schemadisplay
-    name="index.html"
-    fields="interface field_name field_callable"
-    schema="..text.ITextIndex"
-    label="Text Index"
-    permission="zope.ManageServices"
-    menu="zmi_views" title="Configuration"
-    />
-
-</zope:configure>

Copied: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/browser/configure.zcml (from rev 94477, zope.app.catalog/trunk/src/zope/app/catalog/browser/configure.zcml)
===================================================================
--- zope.app.catalog/tags/3.6.0/src/zope/app/catalog/browser/configure.zcml	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/browser/configure.zcml	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,141 @@
+<zope:configure
+   xmlns:zope="http://namespaces.zope.org/zope"
+   xmlns="http://namespaces.zope.org/browser"
+   i18n_domain="zope"
+   >
+
+<!-- Allow a catalog to be added to content space -->
+<addMenuItem
+    title="Catalog"
+    description="A Catalog allows indexing and searching of objects"
+    class="zope.app.catalog.catalog.Catalog"
+    permission="zope.ManageContent"
+    />
+
+<icon
+    name="zmi_icon"
+    for="zope.app.catalog.interfaces.ICatalog"
+    file="catalog_icon.gif"
+    />
+
+<containerViews
+     for="..interfaces.ICatalog"
+     contents="zope.ManageServices"
+     index="zope.ManageServices"
+     add="zope.ManageServices"
+     />
+
+<pages
+    for="..interfaces.ICatalog"
+    class=".catalog.Advanced"
+    permission="zope.ManageContent">
+
+  <page name="advanced.html" template="advanced.pt"
+        menu="zmi_views" title="Advanced"/>
+  <page name="reindex.html" attribute="reindex"/>
+</pages>
+
+<!-- Indexes -->
+
+<addform
+    name="AddFieldIndex"
+    label="Add a field index"
+    schema="..interfaces.IAttributeIndex"
+    permission="zope.ManageServices"
+    content_factory="..field.FieldIndex"
+    arguments="field_name"
+    keyword_arguments="interface field_callable"
+    />
+
+<addMenuItem
+    title="Field Index"
+    description="Index items based on an orderable field value"
+    class="..field.FieldIndex"
+    permission="zope.ManageServices"
+    view="AddFieldIndex"
+   />
+
+<schemadisplay
+    name="index.html"
+    schema="..field.IFieldIndex"
+    label="Field Index"
+    fields="interface field_name field_callable"
+    permission="zope.ManageServices"
+    menu="zmi_views" title="Configuration"
+    />
+
+<addform
+    name="AddKeywordIndex"
+    label="Add a keyword index"
+    schema="..interfaces.IAttributeIndex"
+    permission="zope.ManageServices"
+    content_factory="..keyword.KeywordIndex"
+    arguments="field_name"
+    keyword_arguments="interface field_callable"
+    />
+
+<addMenuItem
+    title="Keyword Index"
+    description="Index items based on sequence of keywords"
+    class="..keyword.KeywordIndex"
+    permission="zope.ManageServices"
+    view="AddKeywordIndex"
+   />
+
+<addform
+    name="AddCaseInsensitiveKeywordIndex"
+    label="Add a keyword index (case-omsensitive)"
+    schema="..interfaces.IAttributeIndex"
+    permission="zope.ManageServices"
+    content_factory="..keyword.CaseInsensitiveKeywordIndex"
+    arguments="field_name"
+    keyword_arguments="interface field_callable"
+    />
+
+<addMenuItem
+    title="Keyword Index (case-insensitive)"
+    description="Index items based on sequence of keywords"
+    class="..keyword.CaseInsensitiveKeywordIndex"
+    permission="zope.ManageServices"
+    view="AddCaseInsensitiveKeywordIndex"
+   />
+
+<schemadisplay
+    name="index.html"
+    schema="..keyword.IKeywordIndex"
+    label="Keyword Index"
+    fields="interface field_name field_callable"
+    permission="zope.ManageServices"
+    menu="zmi_views" title="Configuration"
+    />
+
+<addform
+    name="AddTextIndex"
+    label="Add a text index"
+    schema="..text.ITextIndex"
+    fields="interface field_name field_callable"
+    permission="zope.ManageServices"
+    content_factory="..text.TextIndex"
+    arguments="field_name"
+    keyword_arguments="interface field_callable"
+    />
+
+<addMenuItem
+    title="Text Index"
+    description="Index items based on multi-value fields with
+                 orderable values"
+    class="..text.TextIndex"
+    permission="zope.ManageServices"
+    view="AddTextIndex"
+   />
+
+<schemadisplay
+    name="index.html"
+    fields="interface field_name field_callable"
+    schema="..text.ITextIndex"
+    label="Text Index"
+    permission="zope.ManageServices"
+    menu="zmi_views" title="Configuration"
+    />
+
+</zope:configure>

Deleted: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/catalog.py
===================================================================
--- zope.app.catalog/trunk/src/zope/app/catalog/catalog.py	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/catalog.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,191 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (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.
-#
-##############################################################################
-"""Catalog
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-import BTrees
-
-import zope.index.interfaces
-from zope import component
-from zope.interface import implements
-from zope.annotation.interfaces import IAttributeAnnotatable
-
-from zope.app.container.interfaces import IContainer
-from zope.app.container.btree import BTreeContainer
-from zope.app.catalog.interfaces import ICatalog, INoAutoIndex, INoAutoReindex
-from zope.app.intid.interfaces import IIntIds
-from zope.traversing.interfaces import IPhysicallyLocatable
-from zope.location import location
-
-
-class ResultSet:
-    """Lazily accessed set of objects."""
-
-    def __init__(self, uids, uidutil):
-        self.uids = uids
-        self.uidutil = uidutil
-
-    def __len__(self):
-        return len(self.uids)
-
-    def __iter__(self):
-        for uid in self.uids:
-            obj = self.uidutil.getObject(uid)
-            yield obj
-
-
-class Catalog(BTreeContainer):
-
-    implements(ICatalog,
-               IContainer,
-               IAttributeAnnotatable,
-               zope.index.interfaces.IIndexSearch,
-               )
-
-    family = BTrees.family32
-
-    def __init__(self, family=None):
-        super(Catalog, self).__init__()
-        if family is not None:
-            self.family = family
-
-    def clear(self):
-        for index in self.values():
-            index.clear()
-
-    def index_doc(self, docid, texts):
-        """Register the data in indexes of this catalog."""
-        for index in self.values():
-            index.index_doc(docid, texts)
-
-    def unindex_doc(self, docid):
-        """Unregister the data from indexes of this catalog."""
-        for index in self.values():
-            index.unindex_doc(docid)
-
-    def _visitSublocations(self) :
-        """Restricts the access to the objects that live within
-        the nearest site if the catalog itself is locatable.
-        """
-        uidutil = None
-        locatable = IPhysicallyLocatable(self, None)
-        if locatable is not None :
-            site = locatable.getNearestSite()
-            sm = site.getSiteManager()
-            uidutil = sm.queryUtility(IIntIds)
-            if uidutil not in [c.component for c in sm.registeredUtilities()]:
-                # we do not have a local inits utility
-                uidutil = component.getUtility(IIntIds, context=self)
-                for uid in uidutil:
-                    obj = uidutil.getObject(uid)
-                    if location.inside(obj, site) :
-                        yield uid, obj
-                return
-        if uidutil is None:
-            uidutil = component.getUtility(IIntIds)
-        for uid in uidutil:
-            yield uid, uidutil.getObject(uid)
-
-    def updateIndex(self, index):
-        for uid, obj in self._visitSublocations() :
-            index.index_doc(uid, obj)
-
-    def updateIndexes(self):
-        for uid, obj in self._visitSublocations() :
-            for index in self.values():
-                index.index_doc(uid, obj)
-
-    def apply(self, query):
-        results = []
-        for index_name, index_query in query.items():
-            index = self[index_name]
-            r = index.apply(index_query)
-            if r is None:
-                continue
-            if not r:
-                # empty results
-                return r
-            results.append((len(r), r))
-
-        if not results:
-            # no applicable indexes, so catalog was not applicable
-            return None
-
-        results.sort() # order from smallest to largest
-
-        _, result = results.pop(0)
-        for _, r in results:
-            _, result = self.family.IF.weightedIntersection(result, r)
-
-        return result
-
-    def searchResults(self, **searchterms):
-        results = self.apply(searchterms)
-        if results is not None:
-            uidutil = component.getUtility(IIntIds)
-            results = ResultSet(results, uidutil)
-        return results
-
-def indexAdded(index, event):
-    """When an index is added to a catalog, we have to index existing objects
-
-       When an index is added, we tell it's parent to index it:
-
-         >>> class FauxCatalog:
-         ...     def updateIndex(self, index):
-         ...         self.updated = index
-
-         >>> class FauxIndex:
-         ...     pass
-
-         >>> index = FauxIndex()
-         >>> index.__parent__ = FauxCatalog()
-
-         >>> indexAdded(index, None)
-         >>> index.__parent__.updated is index
-         True
-       """
-    index.__parent__.updateIndex(index)
-
-def indexDocSubscriber(event):
-    """A subscriber to IntIdAddedEvent"""
-    ob = event.object
-    if INoAutoIndex.providedBy(ob):
-        return
-    for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=ob):
-        id = component.getUtility(IIntIds, context=cat).getId(ob)
-        cat.index_doc(id, ob)
-
-
-def reindexDocSubscriber(event):
-    """A subscriber to ObjectModifiedEvent"""
-    ob = event.object
-    if INoAutoReindex.providedBy(ob):
-        return
-    for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=ob):
-        id = component.getUtility(IIntIds, context=cat).queryId(ob)
-        if id is not None:
-            cat.index_doc(id, ob)
-
-
-def unindexDocSubscriber(event):
-    """A subscriber to IntIdRemovedEvent"""
-    ob = event.object
-    for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=ob):
-        id = component.getUtility(IIntIds, context=cat).queryId(ob)
-        if id is not None:
-            cat.unindex_doc(id)

Copied: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/catalog.py (from rev 94477, zope.app.catalog/trunk/src/zope/app/catalog/catalog.py)
===================================================================
--- zope.app.catalog/tags/3.6.0/src/zope/app/catalog/catalog.py	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/catalog.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,206 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Catalog
+
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+import BTrees
+
+import zope.index.interfaces
+from zope import component
+from zope.interface import implements
+from zope.annotation.interfaces import IAttributeAnnotatable
+
+from zope.app.container.interfaces import IContainer
+from zope.app.container.btree import BTreeContainer
+from zope.app.catalog.interfaces import ICatalog, INoAutoIndex, INoAutoReindex
+from zope.app.intid.interfaces import IIntIds
+from zope.traversing.interfaces import IPhysicallyLocatable
+from zope.location import location
+
+
+class ResultSet:
+    """Lazily accessed set of objects."""
+
+    def __init__(self, uids, uidutil):
+        self.uids = uids
+        self.uidutil = uidutil
+
+    def __len__(self):
+        return len(self.uids)
+
+    def __iter__(self):
+        for uid in self.uids:
+            obj = self.uidutil.getObject(uid)
+            yield obj
+
+
+class Catalog(BTreeContainer):
+
+    implements(ICatalog,
+               IContainer,
+               IAttributeAnnotatable,
+               zope.index.interfaces.IIndexSearch,
+               )
+
+    family = BTrees.family32
+
+    def __init__(self, family=None):
+        super(Catalog, self).__init__()
+        if family is not None:
+            self.family = family
+
+    def clear(self):
+        for index in self.values():
+            index.clear()
+
+    def index_doc(self, docid, texts):
+        """Register the data in indexes of this catalog."""
+        for index in self.values():
+            index.index_doc(docid, texts)
+
+    def unindex_doc(self, docid):
+        """Unregister the data from indexes of this catalog."""
+        for index in self.values():
+            index.unindex_doc(docid)
+
+    def _visitSublocations(self) :
+        """Restricts the access to the objects that live within
+        the nearest site if the catalog itself is locatable.
+        """
+        uidutil = None
+        locatable = IPhysicallyLocatable(self, None)
+        if locatable is not None :
+            site = locatable.getNearestSite()
+            sm = site.getSiteManager()
+            uidutil = sm.queryUtility(IIntIds)
+            if uidutil not in [c.component for c in sm.registeredUtilities()]:
+                # we do not have a local inits utility
+                uidutil = component.getUtility(IIntIds, context=self)
+                for uid in uidutil:
+                    obj = uidutil.getObject(uid)
+                    if location.inside(obj, site) :
+                        yield uid, obj
+                return
+        if uidutil is None:
+            uidutil = component.getUtility(IIntIds)
+        for uid in uidutil:
+            yield uid, uidutil.getObject(uid)
+
+    def updateIndex(self, index):
+        for uid, obj in self._visitSublocations() :
+            index.index_doc(uid, obj)
+
+    def updateIndexes(self):
+        for uid, obj in self._visitSublocations() :
+            for index in self.values():
+                index.index_doc(uid, obj)
+
+    def apply(self, query):
+        results = []
+        for index_name, index_query in query.items():
+            index = self[index_name]
+            r = index.apply(index_query)
+            if r is None:
+                continue
+            if not r:
+                # empty results
+                return r
+            results.append((len(r), r))
+
+        if not results:
+            # no applicable indexes, so catalog was not applicable
+            return None
+
+        results.sort() # order from smallest to largest
+
+        _, result = results.pop(0)
+        for _, r in results:
+            _, result = self.family.IF.weightedIntersection(result, r)
+
+        return result
+
+    def searchResults(self, **searchterms):
+        sort_index = searchterms.pop('_sort_index', None)
+        limit = searchterms.pop('_limit', None)
+        reverse = searchterms.pop('_reverse', False)
+        results = self.apply(searchterms)
+        if results is not None:
+            if sort_index is not None:
+                index = self[sort_index]
+                if not zope.index.interfaces.IIndexSort.providedBy(index):
+                    raise ValueError('Index %s does not support sorting.' % sort_index)
+                results = list(index.sort(results, limit=limit, reverse=reverse))
+            else:
+                if reverse or limit:
+                    results = list(results)
+                if reverse:
+                    results.reverse()
+                if limit:
+                    del results[limit:]
+            uidutil = component.getUtility(IIntIds)
+            results = ResultSet(results, uidutil)
+        return results
+
+def indexAdded(index, event):
+    """When an index is added to a catalog, we have to index existing objects
+
+       When an index is added, we tell it's parent to index it:
+
+         >>> class FauxCatalog:
+         ...     def updateIndex(self, index):
+         ...         self.updated = index
+
+         >>> class FauxIndex:
+         ...     pass
+
+         >>> index = FauxIndex()
+         >>> index.__parent__ = FauxCatalog()
+
+         >>> indexAdded(index, None)
+         >>> index.__parent__.updated is index
+         True
+       """
+    index.__parent__.updateIndex(index)
+
+def indexDocSubscriber(event):
+    """A subscriber to IntIdAddedEvent"""
+    ob = event.object
+    if INoAutoIndex.providedBy(ob):
+        return
+    for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=ob):
+        id = component.getUtility(IIntIds, context=cat).getId(ob)
+        cat.index_doc(id, ob)
+
+
+def reindexDocSubscriber(event):
+    """A subscriber to ObjectModifiedEvent"""
+    ob = event.object
+    if INoAutoReindex.providedBy(ob):
+        return
+    for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=ob):
+        id = component.getUtility(IIntIds, context=cat).queryId(ob)
+        if id is not None:
+            cat.index_doc(id, ob)
+
+
+def unindexDocSubscriber(event):
+    """A subscriber to IntIdRemovedEvent"""
+    ob = event.object
+    for cat in component.getAllUtilitiesRegisteredFor(ICatalog, context=ob):
+        id = component.getUtility(IIntIds, context=cat).queryId(ob)
+        if id is not None:
+            cat.unindex_doc(id)

Deleted: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/classes.zcml
===================================================================
--- zope.app.catalog/trunk/src/zope/app/catalog/classes.zcml	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/classes.zcml	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configure
-    xmlns="http://namespaces.zope.org/zope"
-    xmlns:browser="http://namespaces.zope.org/browser"
-    >
-
-  <class class=".catalog.Catalog">
-    <factory
-        id="zope.app.catalog"
-        />
-    <implements
-        interface="zope.annotation.interfaces.IAttributeAnnotatable"
-        />
-    <require
-        interface="zope.app.catalog.interfaces.ICatalogQuery"
-        permission="zope.Public"
-        />
-    <require
-        interface="zope.app.catalog.interfaces.ICatalogEdit"
-        permission="zope.ManageServices"
-        />
-    <require
-        interface="zope.app.container.interfaces.IContainer"
-        permission="zope.ManageServices"
-        />
-  </class>
-
-  <class class=".catalog.ResultSet">
-    <require
-        attributes="__iter__ __len__"
-        permission="zope.Public"
-        />
-  </class>
-
-  <class class=".field.FieldIndex">
-    <require
-        permission="zope.ManageServices"
-        interface=".interfaces.IAttributeIndex
-                   zope.index.interfaces.IStatistics
-                  "
-        set_schema=".interfaces.IAttributeIndex"
-        />
-  </class>
-
-  <class class=".text.TextIndex">
-    <require
-        permission="zope.ManageServices"
-        interface=".interfaces.IAttributeIndex
-                   zope.index.interfaces.IStatistics
-                  "
-        set_schema=".interfaces.IAttributeIndex"
-        />
-  </class>
-
-  <interface interface="zope.index.text.interfaces.ISearchableText" />
-
-</configure>

Copied: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/classes.zcml (from rev 94477, zope.app.catalog/trunk/src/zope/app/catalog/classes.zcml)
===================================================================
--- zope.app.catalog/tags/3.6.0/src/zope/app/catalog/classes.zcml	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/classes.zcml	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    >
+
+  <class class=".catalog.Catalog">
+    <factory
+        id="zope.app.catalog"
+        />
+    <implements
+        interface="zope.annotation.interfaces.IAttributeAnnotatable"
+        />
+    <require
+        interface="zope.app.catalog.interfaces.ICatalogQuery"
+        permission="zope.Public"
+        />
+    <require
+        interface="zope.app.catalog.interfaces.ICatalogEdit"
+        permission="zope.ManageServices"
+        />
+    <require
+        interface="zope.app.container.interfaces.IContainer"
+        permission="zope.ManageServices"
+        />
+  </class>
+
+  <class class=".catalog.ResultSet">
+    <require
+        attributes="__iter__ __len__"
+        permission="zope.Public"
+        />
+  </class>
+
+  <class class=".field.FieldIndex">
+    <require
+        permission="zope.ManageServices"
+        interface=".interfaces.IAttributeIndex
+                   zope.index.interfaces.IStatistics
+                  "
+        set_schema=".interfaces.IAttributeIndex"
+        />
+  </class>
+
+  <class class=".keyword.KeywordIndex">
+    <require
+        permission="zope.ManageServices"
+        interface=".interfaces.IAttributeIndex
+                   zope.index.interfaces.IStatistics"
+        set_schema=".interfaces.IAttributeIndex"
+        />
+  </class>
+
+  <class class=".keyword.CaseInsensitiveKeywordIndex">
+    <require like_class=".keyword.KeywordIndex" /> 
+  </class>
+
+  <class class=".text.TextIndex">
+    <require
+        permission="zope.ManageServices"
+        interface=".interfaces.IAttributeIndex
+                   zope.index.interfaces.IStatistics
+                  "
+        set_schema=".interfaces.IAttributeIndex"
+        />
+  </class>
+
+  <interface interface="zope.index.text.interfaces.ISearchableText" />
+
+</configure>

Deleted: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/interfaces.py
===================================================================
--- zope.app.catalog/trunk/src/zope/app/catalog/interfaces.py	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/interfaces.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,88 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (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.
-#
-##############################################################################
-"""Catalog Interfaces
-
-$Id$
-"""
-
-import zope.index.interfaces
-import zope.interface
-import zope.schema
-import zope.app.container.interfaces
-import zope.app.container.constraints
-
-from zope.i18nmessageid import ZopeMessageFactory as _
-
-class ICatalogQuery(zope.interface.Interface):
-    """Provides Catalog Queries."""
-
-    def searchResults(**kw):
-        """Search on the given indexes."""
-
-
-class ICatalogEdit(zope.index.interfaces.IInjection):
-    """Allows one to manipulate the Catalog information."""
-
-    def updateIndexes():
-        """Reindex all objects."""
-
-
-class ICatalogIndex(zope.index.interfaces.IInjection,
-                    zope.index.interfaces.IIndexSearch,
-                    ):
-    """An index to be used in a catalog
-    """
-    __parent__ = zope.schema.Field()
-    
-
-class ICatalog(ICatalogQuery, ICatalogEdit,
-               zope.app.container.interfaces.IContainer): 
-    """Marker to describe a catalog in content space."""
-
-    zope.app.container.constraints.contains(ICatalogIndex)
-
-ICatalogIndex['__parent__'].constraint = (
-    zope.app.container.constraints.ContainerTypesConstraint(ICatalog))
-
-class IAttributeIndex(zope.interface.Interface):
-    """I index objects by first adapting them to an interface, then
-       retrieving a field on the adapted object.
-    """
-
-    interface = zope.schema.Choice(
-        title=_(u"Interface"),
-        description=_(u"Objects will be adapted to this interface"),
-        vocabulary="Interfaces",
-        required=False,
-        )
-
-    field_name = zope.schema.BytesLine(
-        title=_(u"Field Name"),
-        description=_(u"Name of the field to index"),
-        )
-
-    field_callable = zope.schema.Bool(
-        title=_(u"Field Callable"),
-        description=_(u"If true, then the field should be called to get the "
-                      u"value to be indexed"),
-        )
-
-
-class INoAutoIndex(zope.interface.Interface):
-
-    """Marker for objects that should not be automatically indexed"""
-
-class INoAutoReindex(zope.interface.Interface):
-
-    """Marker for objects that should not be automatically reindexed"""

Copied: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/interfaces.py (from rev 94477, zope.app.catalog/trunk/src/zope/app/catalog/interfaces.py)
===================================================================
--- zope.app.catalog/tags/3.6.0/src/zope/app/catalog/interfaces.py	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/interfaces.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,105 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Catalog Interfaces
+
+$Id$
+"""
+
+import zope.index.interfaces
+import zope.interface
+import zope.schema
+import zope.app.container.interfaces
+import zope.app.container.constraints
+
+from zope.i18nmessageid import ZopeMessageFactory as _
+
+class ICatalogQuery(zope.interface.Interface):
+    """Provides Catalog Queries."""
+
+    def searchResults(**kw):
+        """Search on the given indexes.
+        
+        Keyword arguments dictionary keys
+        are index names and values are queries
+        for these indexes.
+        
+        Keyword arguments has some special names,
+        used by the catalog itself:
+        
+         * _sort_index - The name of index to sort
+           results with. This index must implement
+           zope.index.interfaces.IIndexSort.
+         * _limit - Limit result set by this number,
+           useful when used with sorting.
+         * _reverse - Reverse result set, also
+           useful with sorting.
+
+        """
+
+
+class ICatalogEdit(zope.index.interfaces.IInjection):
+    """Allows one to manipulate the Catalog information."""
+
+    def updateIndexes():
+        """Reindex all objects."""
+
+
+class ICatalogIndex(zope.index.interfaces.IInjection,
+                    zope.index.interfaces.IIndexSearch,
+                    ):
+    """An index to be used in a catalog
+    """
+    __parent__ = zope.schema.Field()
+    
+
+class ICatalog(ICatalogQuery, ICatalogEdit,
+               zope.app.container.interfaces.IContainer): 
+    """Marker to describe a catalog in content space."""
+
+    zope.app.container.constraints.contains(ICatalogIndex)
+
+ICatalogIndex['__parent__'].constraint = (
+    zope.app.container.constraints.ContainerTypesConstraint(ICatalog))
+
+class IAttributeIndex(zope.interface.Interface):
+    """I index objects by first adapting them to an interface, then
+       retrieving a field on the adapted object.
+    """
+
+    interface = zope.schema.Choice(
+        title=_(u"Interface"),
+        description=_(u"Objects will be adapted to this interface"),
+        vocabulary="Interfaces",
+        required=False,
+        )
+
+    field_name = zope.schema.BytesLine(
+        title=_(u"Field Name"),
+        description=_(u"Name of the field to index"),
+        )
+
+    field_callable = zope.schema.Bool(
+        title=_(u"Field Callable"),
+        description=_(u"If true, then the field should be called to get the "
+                      u"value to be indexed"),
+        )
+
+
+class INoAutoIndex(zope.interface.Interface):
+
+    """Marker for objects that should not be automatically indexed"""
+
+class INoAutoReindex(zope.interface.Interface):
+
+    """Marker for objects that should not be automatically reindexed"""

Copied: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/keyword.py (from rev 94477, zope.app.catalog/trunk/src/zope/app/catalog/keyword.py)
===================================================================
--- zope.app.catalog/tags/3.6.0/src/zope/app/catalog/keyword.py	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/keyword.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,39 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Keyword catalog index
+
+$Id:$
+"""
+import zope.index.keyword
+import zope.interface
+
+import zope.app.container.contained
+import zope.app.catalog.attribute
+import zope.app.catalog.interfaces
+
+class IKeywordIndex(zope.app.catalog.interfaces.IAttributeIndex,
+                     zope.app.catalog.interfaces.ICatalogIndex):
+    """Interface-based catalog keyword index"""
+
+class KeywordIndex(zope.app.catalog.attribute.AttributeIndex,
+                    zope.index.keyword.KeywordIndex,
+                    zope.app.container.contained.Contained):
+
+    zope.interface.implements(IKeywordIndex)
+
+class CaseInsensitiveKeywordIndex(zope.app.catalog.attribute.AttributeIndex,
+                                      zope.index.keyword.CaseInsensitiveKeywordIndex,
+                                      zope.app.container.contained.Contained):
+
+    zope.interface.implements(IKeywordIndex)

Deleted: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/text.py
===================================================================
--- zope.app.catalog/trunk/src/zope/app/catalog/text.py	2009-01-03 15:21:36 UTC (rev 94476)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/text.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -1,57 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (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.
-#
-##############################################################################
-"""Text catalog indexes
-
-$Id$
-"""
-import zope.index.text
-import zope.index.text.interfaces
-import zope.interface
-
-import zope.app.catalog.attribute
-import zope.app.catalog.interfaces
-import zope.app.container.contained
-from zope.i18nmessageid import ZopeMessageFactory as _
-
-class ITextIndex(zope.app.catalog.interfaces.IAttributeIndex,
-                 zope.app.catalog.interfaces.ICatalogIndex):
-    """Interface-based catalog text index
-    """
-
-    interface = zope.schema.Choice(
-        title=_(u"Interface"),
-        description=_(u"Objects will be adapted to this interface"),
-        vocabulary=_("Interfaces"),
-        required=False,
-        default=zope.index.text.interfaces.ISearchableText,
-        )
-
-    field_name = zope.schema.BytesLine(
-        title=_(u"Field Name"),
-        description=_(u"Name of the field to index"),
-        default="searchableText"
-        )
-
-    field_callable = zope.schema.Bool(
-        title=_(u"Field Callable"),
-        description=_(u"If true, then the field should be called to get the "
-                      u"value to be indexed"),
-        default=True,
-        )
-
-class TextIndex(zope.app.catalog.attribute.AttributeIndex,
-                zope.index.text.TextIndex,
-                zope.app.container.contained.Contained):
-
-    zope.interface.implements(ITextIndex)

Copied: zope.app.catalog/tags/3.6.0/src/zope/app/catalog/text.py (from rev 94477, zope.app.catalog/trunk/src/zope/app/catalog/text.py)
===================================================================
--- zope.app.catalog/tags/3.6.0/src/zope/app/catalog/text.py	                        (rev 0)
+++ zope.app.catalog/tags/3.6.0/src/zope/app/catalog/text.py	2009-01-03 15:41:02 UTC (rev 94479)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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.
+#
+##############################################################################
+"""Text catalog indexes
+
+$Id$
+"""
+import zope.index.text
+import zope.index.text.interfaces
+import zope.interface
+
+import zope.app.catalog.attribute
+import zope.app.catalog.interfaces
+import zope.app.container.contained
+from zope.i18nmessageid import ZopeMessageFactory as _
+
+class ITextIndex(zope.app.catalog.interfaces.IAttributeIndex,
+                 zope.app.catalog.interfaces.ICatalogIndex):
+    """Interface-based catalog text index
+    """
+
+    interface = zope.schema.Choice(
+        title=_(u"Interface"),
+        description=_(u"Objects will be adapted to this interface"),
+        vocabulary=_("Interfaces"),
+        required=False,
+        default=zope.index.text.interfaces.ISearchableText,
+        )
+
+    field_name = zope.schema.BytesLine(
+        title=_(u"Field Name"),
+        description=_(u"Name of the field to index"),
+        default="getSearchableText"
+        )
+
+    field_callable = zope.schema.Bool(
+        title=_(u"Field Callable"),
+        description=_(u"If true, then the field should be called to get the "
+                      u"value to be indexed"),
+        default=True,
+        )
+
+class TextIndex(zope.app.catalog.attribute.AttributeIndex,
+                zope.index.text.TextIndex,
+                zope.app.container.contained.Contained):
+
+    zope.interface.implements(ITextIndex)



More information about the Checkins mailing list