[Zope3-checkins] SVN: Zope3/trunk/src/optionstorage/ Adding "optionstorage" product to src/, as requested by Stephan Richter.

Gustavo Niemeyer niemeyer at conectiva.com
Fri Nov 12 13:49:40 EST 2004


Log message for revision 28445:
  Adding "optionstorage" product to src/, as requested by Stephan Richter.
  
  This is a generic solution for including editable and multi-lingual
  vocbulary-like information in any annotatable object.
  

Changed:
  A   Zope3/trunk/src/optionstorage/
  A   Zope3/trunk/src/optionstorage/__init__.py
  A   Zope3/trunk/src/optionstorage/browser/
  A   Zope3/trunk/src/optionstorage/browser/__init__.py
  A   Zope3/trunk/src/optionstorage/browser/configure.zcml
  A   Zope3/trunk/src/optionstorage/browser/meta.zcml
  A   Zope3/trunk/src/optionstorage/browser/metaconfigure.py
  A   Zope3/trunk/src/optionstorage/browser/metadirectives.py
  A   Zope3/trunk/src/optionstorage/browser/optiondict.pt
  A   Zope3/trunk/src/optionstorage/browser/optionstorage.pt
  A   Zope3/trunk/src/optionstorage/browser/widgets.py
  A   Zope3/trunk/src/optionstorage/configure.zcml
  A   Zope3/trunk/src/optionstorage/interfaces.py
  A   Zope3/trunk/src/optionstorage/meta.zcml
  A   Zope3/trunk/src/optionstorage/metaconfigure.py
  A   Zope3/trunk/src/optionstorage/metadirectives.py
  A   Zope3/trunk/src/optionstorage/vocabulary.py

-=-
Added: Zope3/trunk/src/optionstorage/__init__.py
===================================================================
--- Zope3/trunk/src/optionstorage/__init__.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/__init__.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,215 @@
+from zope.app.annotation.interfaces import IAnnotatable, IAnnotations
+from zope.proxy import removeAllProxies
+from zope.interface import implements
+from zope.app import zapi
+
+from persistent.dict import PersistentDict
+from persistent import Persistent
+
+from interfaces import IOptionStorage, IOptionDict
+
+from UserDict import IterableUserDict
+
+OptionStorageKey = "optionstorage"
+
+class Table(object):
+    # Based on zope's SecurityMap.
+
+    def __init__(self):
+        self._byrow = {}
+        self._bycol = {}
+
+    def __nonzero__(self):
+        return bool(self._byrow)
+
+    def _changed(self):
+        pass
+
+    def clear(self):
+        self._byrow.clear()
+        self._bycol.clear()
+        self._changed()
+
+    def addCell(self, rowkey, colkey, value):
+        row = self._byrow.get(rowkey)
+        if row:
+            if row.get(colkey) is value:
+                return False
+        else:
+            row = self._byrow[rowkey] = {}
+
+        col = self._bycol.get(colkey)
+        if not col:
+            col = self._bycol[colkey] = {}
+            
+        row[colkey] = value
+        col[rowkey] = value
+        
+        self._changed()
+
+        return True
+
+    def delCell(self, rowkey, colkey):
+        row = self._byrow.get(rowkey)
+        if row and (colkey in row):
+            del row[colkey]
+            if not row:
+                del self._byrow[rowkey]
+            col = self._bycol[colkey]
+            del col[rowkey]
+            if not col:
+                del self._bycol[colkey]
+            return True
+
+        self._changed()
+
+        return False
+
+    def queryCell(self, rowkey, colkey, default=None):
+        row = self._byrow.get(rowkey)
+        if row:
+            return row.get(colkey, default)
+        else:
+            return default
+
+    def getCell(self, rowkey, colkey):
+        marker = object()
+        cell = self.queryCell(rowkey, colkey, marker)
+        if cell is marker:
+            raise KeyError, "Invalid row/column pair"
+        return cell
+
+    def getRow(self, rowkey):
+        row = self._byrow.get(rowkey)
+        if row:
+            return row.items()
+        else:
+            return []
+
+    def getCol(self, colkey):
+        col = self._bycol.get(colkey)
+        if col:
+            return col.items()
+        else:
+            return []
+
+    def getRowKeys(self):
+        return self._byrow.keys()
+
+    def getColKeys(self):
+        return self._bycol.keys()
+
+    def getAllCells(self):
+        res = []
+        for r in self._byrow.keys():
+            for c in self._byrow[r].items():
+                res.append((r,) + c)
+        return res
+
+
+class PersistentTable(Table, Persistent):
+
+    def _changed(self):
+        self._p_changed = 1
+
+
+class OptionDict(Persistent):
+
+    implements(IOptionDict)
+
+    def __init__(self):
+        self._defaultkey = None
+        self._defaultlanguage = None
+        self._table = PersistentTable()
+
+    def getLanguages(self):
+        return self._table.getColKeys()
+
+    def getDefaultLanguage(self):
+        return self._defaultlanguage
+
+    def setDefaultLanguage(self, language):
+        self._defaultlanguage = language
+
+    def getDefaultKey(self):
+        return self._defaultkey
+
+    def setDefaultKey(self, key):
+        self._defaultkey = key
+
+    def getKeys(self):
+        return self._table.getRowKeys()
+
+    def queryValue(self, key, language, default=None):
+        return self._table.queryCell(key, language, default)
+
+    def getValue(self, key, language):
+        return self._table.getCell(key, language)
+
+    def addValue(self, key, language, value):
+        self._table.addCell(key, language, value)
+
+    def delValue(self, key, language):
+        self._table.delCell(key, language)
+
+    def delAllValues(self):
+        self._table.clear()
+        self._defaultkey = None
+
+
+class OptionStorage(IterableUserDict, object):
+
+    implements(IOptionStorage)
+
+    def __init__(self, context):
+        annotations = IAnnotations(removeAllProxies(context))
+        if OptionStorageKey in annotations:
+            self.data = annotations[OptionStorageKey]
+        else:
+            self.data = annotations[OptionStorageKey] = PersistentDict()
+
+def queryOptionStorage(context, name):
+    lookuplist = zapi.getParents(context)
+    lookuplist.insert(0, context)
+    for object in lookuplist:
+        object = removeAllProxies(object)
+        if IAnnotatable.providedBy(object):
+            annotations = IAnnotations(object)
+            if OptionStorageKey in annotations:
+                storage = IOptionStorage(object)
+                if name in storage:
+                    return storage[name]
+    return None
+
+class OptionStorageProperty(object):
+    
+    def __init__(self, name, dictname, islist=False, readonly=False):
+        self._name = name
+        self._dictname = dictname
+        self._islist = islist
+        self._readonly = readonly
+
+    def __get__(self, object, type_=None):
+        dict = queryOptionStorage(object, self._dictname)
+        if dict:
+            default = dict.getDefaultKey()
+        return getattr(object, self._name, default)
+
+    def __set__(self, object, value):
+        if self._readonly:
+            raise AttributeError, "Attribute '%s' is read-only" % self._name
+        if type(value) is not list:
+            values = [value]
+        else:
+            values = value
+        dict = queryOptionStorage(object, self._dictname)
+        if dict:
+            keys = dict.getKeys()
+            invalid = [x for x in values if x not in keys]
+            if invalid:
+                raise ValueError, "Invalid values: %s" % \
+                                  ", ".join(map(repr, invalid))
+        if self._islist:
+            value = values
+        setattr(object, self._name, value)
+

Added: Zope3/trunk/src/optionstorage/browser/__init__.py
===================================================================
--- Zope3/trunk/src/optionstorage/browser/__init__.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/__init__.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,87 @@
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from optionstorage.interfaces import IOptionStorage
+from optionstorage import OptionDict
+from zope.exceptions import NotFoundError
+
+def checkFields(request, *fields):
+    for field in fields:
+        if field not in request:
+            return False
+    return True
+
+class OptionStorageView(object):
+
+    storagetemplate = ViewPageTemplateFile("optionstorage.pt")
+    dicttemplate = ViewPageTemplateFile("optiondict.pt")
+
+    dictlist = [] # (name, topic)
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+        self.name = None
+        self.topic = None
+        self.dict = None
+
+    def getNameTopicList(self):
+        storage = IOptionStorage(self.context)
+        for name, topic in self.dictlist:
+            yield {"name": name, "topic": topic}
+
+    def __call__(self, name=None):
+        if name is None:
+            return self.storagetemplate()
+
+        storage = IOptionStorage(self.context)
+        for _name, topic in self.dictlist:
+            if name == _name:
+                if name not in storage:
+                    storage[name] = OptionDict()
+                self.dict = storage[name]
+                self.name = name
+                self.topic = topic
+                break
+        else:
+            raise NotFoundError(self.context, name, self.request)
+
+        form = self.request.form
+        if "SAVE" not in form:
+            return self.dicttemplate()
+
+        language = {}
+        key = {}
+        value = {}
+        for entry in form:
+            entryvalue = form[entry].strip()
+            if not entryvalue:
+                pass
+            elif entry.startswith("lang-"):
+                language[int(entry[5:])] = entryvalue
+            elif entry.startswith("key-"):
+                key[int(entry[4:])] = entryvalue
+            elif entry.startswith("value-"):
+                tok = entry.split("-")
+                value[int(tok[1]), int(tok[2])] = entryvalue
+
+        try:
+            defaultkey = int(form["default-key"])
+        except KeyError:
+            defaultkey = None
+
+        try:
+            defaultlanguage = int(form["default-lang"])
+        except KeyError:
+            defaultlanguage = None
+
+        self.dict.delAllValues()
+        for keynum, languagenum in value:
+            if keynum in key and languagenum in language:
+                self.dict.addValue(key[keynum], language[languagenum],
+                                   value[keynum, languagenum])
+        if defaultkey in key:
+            self.dict.setDefaultKey(key[defaultkey])
+        if defaultlanguage in language:
+            self.dict.setDefaultLanguage(language[defaultlanguage])
+
+        return self.dicttemplate()
+

Added: Zope3/trunk/src/optionstorage/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/optionstorage/browser/configure.zcml	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/configure.zcml	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,14 @@
+<configure
+	xmlns="http://namespaces.zope.org/browser"
+	xmlns:zope="http://namespaces.zope.org/zope">
+
+<zope:view
+	type="zope.publisher.interfaces.browser.IBrowserRequest"
+	for="zope.schema.interfaces.IChoice
+	     optionstorage.interfaces.IOptionStorageVocabulary"
+	provides="zope.app.form.interfaces.IInputWidget"
+	factory=".widgets.OptionStorageVocabularyWidget"
+	permission="zope.Public"
+	/>
+
+</configure>

Added: Zope3/trunk/src/optionstorage/browser/meta.zcml
===================================================================
--- Zope3/trunk/src/optionstorage/browser/meta.zcml	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/meta.zcml	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,22 @@
+<configure
+	xmlns="http://namespaces.zope.org/zope"
+	xmlns:meta="http://namespaces.zope.org/meta">
+
+<meta:directives namespace="http://namespaces.zope.org/browser">
+
+<meta:complexDirective
+	name="optionStorage"
+	schema=".metadirectives.IOptionStorageDirective"
+	handler=".metaconfigure.optionStorage"
+	>
+
+	<meta:subdirective
+		name="options"
+		schema=".metadirectives.IOptionStorageOptionsSubdirective"
+		/>
+
+</meta:complexDirective>
+
+</meta:directives>
+
+</configure>

Added: Zope3/trunk/src/optionstorage/browser/metaconfigure.py
===================================================================
--- Zope3/trunk/src/optionstorage/browser/metaconfigure.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/metaconfigure.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,22 @@
+from zope.app.publisher.browser.viewmeta import page
+from optionstorage.browser import OptionStorageView
+
+class optionStorage(object):
+
+    def __init__(self, _context, class_=None, **kwargs):
+        self._context = _context
+        self.class_ = class_
+        self.opts = kwargs.copy()
+        self.dictlist = []
+
+    def options(self, _context, name, topic):
+        self.dictlist.append((name, topic))
+
+    def __call__(self):
+        class_ = self.class_
+        if class_ is None:
+            class_ = OptionStorageView
+        class_ = type("OptionStorageView", (class_,),
+                      {"dictlist": self.dictlist})
+        page(self._context, class_=class_, **self.opts)
+        return ()

Added: Zope3/trunk/src/optionstorage/browser/metadirectives.py
===================================================================
--- Zope3/trunk/src/optionstorage/browser/metadirectives.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/metadirectives.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,24 @@
+from zope.app.publisher.browser.metadirectives import IViewDirective
+from zope.configuration.fields import MessageID
+from zope.interface import Interface
+from zope.schema import TextLine
+
+
+class IOptionStorageDirective(IViewDirective):
+    """
+    The manageableVocabularies directive is used to create a
+    vocabulary editing view for a given interface.
+    """
+
+class IOptionStorageOptionsSubdirective(Interface):
+
+    name = TextLine(
+                   title=u"Key of option dictionary in storage",
+                   required=True,
+                   )
+
+    topic = MessageID(
+                   title=u"Topic of option dictionary in storage",
+                   required=True,
+                   )
+

Added: Zope3/trunk/src/optionstorage/browser/optiondict.pt
===================================================================
--- Zope3/trunk/src/optionstorage/browser/optiondict.pt	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/optiondict.pt	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,61 @@
+<html metal:use-macro="context/@@standard_macros/view">
+<body>
+<div metal:fill-slot="body"
+     tal:define="dict view/dict"
+     i18n:domain="optionstorage">
+
+  <h2 tal:content="view/topic">Some Topic</h2>
+  <br />
+  <form method="post" tal:attributes="action request/URL">
+
+    <input type="hidden" name="name" tal:attributes="value view/name" />
+
+    <table>
+      <!-- Language row -->
+      <tr>
+        <td>&nbsp;</td>
+        <td><center><b i18n:translate="">Keys</b></center></td>
+        <td tal:repeat="language python:dict.getLanguages()+['']">
+          <b i18n:translate="">Language:</b>
+          <input type="text" size="5"
+                 tal:attributes="value language;
+                                 name string:lang-${repeat/language/index}" />
+          <input type="radio" name="default-lang"
+                 tal:attributes="value repeat/language/index;
+                                 checked python:language == dict.getDefaultLanguage()" />
+        </td>
+      </tr>
+      <tr tal:repeat="key python:dict.getKeys()+['']*3">
+        <td>
+          <input type="radio" name="default-key"
+                 tal:attributes="value repeat/key/index;
+                                 checked python:key == dict.getDefaultKey()" />
+        </td>
+        <td>
+          <input type="text" size="10"
+                 tal:attributes="value key;
+                                 name string:key-${repeat/key/index}" />
+        </td>
+        <td tal:repeat="language python:dict.getLanguages()+['']">
+          <input type="text" size="20"
+                 tal:attributes="value python:dict.queryValue(key, language);
+                                 name string:value-${repeat/key/index}-${repeat/language/index}" />
+        </td>
+      </tr>
+
+      <tr>
+        <td colspan="2"><b i18n:translate="">Default</b></td>
+      </tr>
+
+    </table>
+
+    <input type="submit" name="SAVE" value="Save" />
+
+  </form>
+
+</div>
+</body>
+</html>
+
+<!-- vim:ts=2:sw=2:et:ft=html
+ -->

Added: Zope3/trunk/src/optionstorage/browser/optionstorage.pt
===================================================================
--- Zope3/trunk/src/optionstorage/browser/optionstorage.pt	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/optionstorage.pt	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,17 @@
+<html metal:use-macro="context/@@standard_macros/view">
+<body>
+<div metal:fill-slot="body">
+
+<ul>
+  <li tal:repeat="dict view/getNameTopicList">
+    <a tal:attributes="href string:${request/URL}?name=${dict/name}"
+       tal:content="dict/topic" />
+  </li>
+</ul>
+
+</div>
+</body>
+</html>
+
+<!-- vim:ts=2:sw=2:et:ft=html
+ -->

Added: Zope3/trunk/src/optionstorage/browser/widgets.py
===================================================================
--- Zope3/trunk/src/optionstorage/browser/widgets.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/browser/widgets.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,9 @@
+from zope.app.form.browser import DropdownWidget
+
+class OptionStorageVocabularyWidget(DropdownWidget):
+
+    def _getDefault(self):
+        default = self.vocabulary.getDefaultKey()
+        if not default:
+            default = super(OptionStorageVocabularyWidget, self)._getDefault()
+        return default

Added: Zope3/trunk/src/optionstorage/configure.zcml
===================================================================
--- Zope3/trunk/src/optionstorage/configure.zcml	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/configure.zcml	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,34 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+<class class="optionstorage.OptionStorage">
+    <require
+    	permission="zope.View"
+	interface="zope.interface.common.mapping.IReadMapping"
+	/>
+    <require
+    	permission="zope.ManageContent"
+	interface="zope.interface.common.mapping.IWriteMapping"
+	/>
+</class>
+
+<class class="optionstorage.OptionDict">
+    <require
+    	permission="zope.View"
+	interface=".interfaces.IOptionDictRead"
+	/>
+    <require
+    	permission="zope.ManageContent"
+	interface=".interfaces.IOptionDictWrite"
+	/>
+</class>
+
+<adapter
+	factory="optionstorage.OptionStorage"
+	provides="optionstorage.interfaces.IOptionStorage"
+	for="zope.app.annotation.interfaces.IAnnotatable"
+	permission="zope.View"
+	/>
+
+<include package=".browser" />
+
+</configure>

Added: Zope3/trunk/src/optionstorage/interfaces.py
===================================================================
--- Zope3/trunk/src/optionstorage/interfaces.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/interfaces.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,47 @@
+from zope.interface.common.mapping import IMapping
+from zope.interface import Interface
+
+class IOptionDictRead(Interface):
+    """Option dictionary read interface."""
+
+    def getLanguages():
+        """Return available languages."""
+
+    def getDefaultKey():
+        """Return default key."""
+
+    def getKeys():
+        """Return available keys."""
+
+    def queryValue(key, language, default=None):
+        """Return value for key/language pair."""
+
+    def getValue(key, language):
+        """Return value for key/language pair."""
+
+class IOptionDictWrite(Interface):
+    """Option dictionary write interface."""
+
+    def setDefaultKey(key):
+        """Change default key."""
+
+    def addValue(key, language, value):
+        """Add value for a key/language pair."""
+
+    def delValue(key, language):
+        """Delete value for a key/language pair."""
+
+    def delAllValues():
+        """Delete all values."""
+
+class IOptionDict(IOptionDictRead,IOptionDictWrite):
+    """Option dictionary."""
+
+class IOptionStorage(IMapping):
+    """Option storage, mapping names to option dictionaries."""
+
+class IOptionStorageVocabulary(Interface):
+
+    def getDefaultKey():
+        """Return default key for an option storage vocabulary."""
+

Added: Zope3/trunk/src/optionstorage/meta.zcml
===================================================================
--- Zope3/trunk/src/optionstorage/meta.zcml	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/meta.zcml	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,14 @@
+<configure
+	xmlns="http://namespaces.zope.org/zope"
+	xmlns:meta="http://namespaces.zope.org/meta">
+
+<meta:directive
+	namespace="http://namespaces.zope.org/zope"
+	name="optionStorageVocabulary"
+	schema=".metadirectives.IOptionStorageVocabularyDirective"
+	handler=".metaconfigure.optionStorageVocabulary"
+	/>
+
+<include package=".browser" file="meta.zcml" />
+
+</configure>

Added: Zope3/trunk/src/optionstorage/metaconfigure.py
===================================================================
--- Zope3/trunk/src/optionstorage/metaconfigure.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/metaconfigure.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,7 @@
+from optionstorage.vocabulary import OptionStorageVocabulary
+from zope.app.schema.metaconfigure import vocabulary
+
+def optionStorageVocabulary(_context, name):
+    def factory(object, name=name):
+        return OptionStorageVocabulary(object, name=name)
+    vocabulary(_context, name, factory)

Added: Zope3/trunk/src/optionstorage/metadirectives.py
===================================================================
--- Zope3/trunk/src/optionstorage/metadirectives.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/metadirectives.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,13 @@
+from zope.interface import Interface
+from zope.schema import TextLine
+
+class IOptionStorageVocabularyDirective(Interface):
+    """
+    Define a named vocabulary fetching information from an option storage.
+    """
+
+    name = TextLine(
+                title=u"Name",
+                description=u"Provides the name for the option storage "\
+                            u"vocabulary.",
+                required=True)

Added: Zope3/trunk/src/optionstorage/vocabulary.py
===================================================================
--- Zope3/trunk/src/optionstorage/vocabulary.py	2004-11-12 15:11:54 UTC (rev 28444)
+++ Zope3/trunk/src/optionstorage/vocabulary.py	2004-11-12 18:49:40 UTC (rev 28445)
@@ -0,0 +1,83 @@
+from zope.schema.interfaces import IVocabularyTokenized
+from zope.schema.vocabulary import SimpleTerm
+from zope.interface import implements
+from zope.app import zapi
+
+from zope.security.management import getInteraction
+from zope.i18n.negotiator import negotiator
+
+from optionstorage.interfaces import IOptionStorage, IOptionStorageVocabulary
+from optionstorage import OptionStorageKey, queryOptionStorage
+
+
+class OptionStorageVocabulary(object):
+
+    # Order matters here. We want our multi-view adapter to be chosen
+    # before the IVocabulary default one.
+    implements(IOptionStorageVocabulary, IVocabularyTokenized)
+
+    def __init__(self, context, name):
+        self.dict = queryOptionStorage(context, name)
+        if self.dict:
+            # Workaround. Hopefully, in the future titles will be
+            # computed as a view.
+            interaction = getInteraction()
+            request = interaction.participations[0]
+            self.language = negotiator.getLanguage(self.dict.getLanguages(),
+                                                   request)
+            self.defaultlanguage = self.dict.getDefaultLanguage()
+
+    def __contains__(self, key):
+        if self.dict:
+            try:
+                self.dict.getValue(key, self.language)
+                return True
+            except KeyError:
+                try:
+                    self.dict.getValue(key, self.defaultlanguage)
+                    return True
+                except KeyError:
+                    pass
+        return False
+
+    def getTerm(self, key):
+        if self.dict:
+            try:
+                value = self.dict.getValue(key, self.language)
+                return SimpleTerm(key, title=value)
+            except KeyError:
+                try:
+                    value = self.dict.getValue(key, self.defaultlanguage)
+                    return SimpleTerm(key, title=value)
+                except KeyError:
+                    pass
+        raise LookupError
+
+    def getTermByToken(self, token):
+        return self.getTerm(token)
+
+    def __iter__(self):
+        if self.dict:
+            for key in self.dict.getKeys():
+                try:
+                    yield self.getTerm(key)
+                except LookupError:
+                    pass
+
+    def __len__(self):
+        count = 0
+        if self.dict:
+            marker = object()
+            for key in self.dict.getKeys():
+                if (self.dict.queryValue(key, self.language,
+                                        marker) is not marker
+                    or self.dict.queryValue(key, self.defaultlanguage,
+                                            marker) is not marker):
+                
+                    count += 1
+        return count
+
+    def getDefaultKey(self):
+        if self.dict:
+            return self.dict.getDefaultKey()
+



More information about the Zope3-Checkins mailing list