source: main/waeup.sirp/trunk/src/waeup/sirp/schema/field.py @ 7164

Last change on this file since 7164 was 7137, checked in by Henrik Bettermann, 13 years ago

Set value Id for property svn:keywords in all Python files.

  • Property svn:keywords set to Id
File size: 5.1 KB
Line 
1##
2## field.py
3## Login : <uli@pu.smp.net>
4## Started on  Fri Sep 16 16:02:55 2011 Uli Fouquet
5## $Id: field.py 7137 2011-11-19 08:37:08Z henrik $
6##
7## Copyright (C) 2011 Uli Fouquet
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22"""Special fields.
23"""
24from zope.interface import implements
25from zope.schema import TextLine
26from zope.schema.interfaces import (
27    ITextLine, IBaseVocabulary, ISource, IContextSourceBinder, InvalidValue,)
28from zope.schema.vocabulary import (
29    SimpleVocabulary, getVocabularyRegistry, VocabularyRegistryError)
30
31class CustomizableErrorMsg(object):
32    # Still work in progress
33
34    def __init__(self, not_in_vocab=InvalidValue, **kw):
35        self.not_in_vocab = not_in_vocab
36        return
37
38class TextLineChoice(TextLine, CustomizableErrorMsg):
39    """A TextLine field that also accepts sources, vocabs and values.
40
41    You can use this field like a regular zope.schema.TextLine field.
42
43    You can additionally give `source`, `values` or `vocabulary`
44    parameters which will work mainly as with regular
45    zope.schema.Choice fields (hence the name). Different to
46    `Choice` field, these parameters are not mandatory. Leave them
47    out and you have a regular `TextLine` field.
48
49    If you pass a simple source parameter, only those values are
50    allowed which also appear in the source. The source should of
51    course provide string values as suitable for TextLine fields only!
52
53    If, for example you create a TextLineChoice like this:
54
55      name = TextLineChoice(
56        title = u'Some name',
57        values = [u'foo', u'bar']  # unicode allowed only!
58        )
59
60    any formlib form rendering this field will only accept input u'foo'
61    or u'bar'.
62
63    The main adavantage of this modified TextLine field is to support
64    contextual sources. That means you can define some
65    IContextSourceBinder component that looks up catalogs or something
66    external else and decide then, whether the entered value of a form
67    is allowed or not.
68
69    The code herein is mainly copied over from
70    zope.schema._field.Choice with slight modifications.
71    """
72    implements(ITextLine)
73
74    def __init__(self, values=None, vocabulary=None, source=None, **kw):
75        if vocabulary is not None:
76            assert (isinstance(vocabulary, basestring)
77                    or IBaseVocabulary.providedBy(vocabulary))
78            assert source is None, (
79                "You cannot specify both source and vocabulary.")
80        elif source is not None:
81            vocabulary = source
82
83        assert values is None or vocabulary is None, (
84               "You cannot specify both values and vocabulary.")
85
86        self.vocabulary = None
87        self.vocabularyName = None
88        if values is not None:
89            self.vocabulary = SimpleVocabulary.fromValues(values)
90        elif isinstance(vocabulary, (unicode, str)):
91            self.vocabularyName = vocabulary
92        elif (ISource.providedBy(vocabulary) or
93              IContextSourceBinder.providedBy(vocabulary)):
94            self.vocabulary = vocabulary
95        super(TextLineChoice, self).__init__(**kw)
96        return
97
98    source = property(lambda self: self.vocabulary)
99
100    def bind(self, object):
101        """See zope.schema._bootstrapinterfaces.IField."""
102        clone = super(TextLineChoice, self).bind(object)
103        # get registered vocabulary if needed:
104        if IContextSourceBinder.providedBy(self.vocabulary):
105            clone.vocabulary = self.vocabulary(object)
106            assert ISource.providedBy(clone.vocabulary)
107        elif clone.vocabulary is None and self.vocabularyName is not None:
108            vr = getVocabularyRegistry()
109            clone.vocabulary = vr.get(object, self.vocabularyName)
110            assert ISource.providedBy(clone.vocabulary)
111        return clone
112
113    def _validate(self, value):
114        """First validate against the regular TextLine rules. Then check any
115        vocabularies/sources.
116        """
117        # Do TextLine validation
118        super(TextLineChoice, self)._validate(value)
119
120        # Check allowed value range (the vocabulary part)
121        vocabulary = self.vocabulary
122        if vocabulary is None and self.vocabularyName is not None:
123            vr = getVocabularyRegistry()
124            try:
125                vocabulary = vr.get(None, self.vocabularyName)
126            except VocabularyRegistryError:
127                raise ValueError("Can't validate value without vocabulary")
128        if vocabulary and value not in vocabulary:
129            raise InvalidValue(value)
130        return
Note: See TracBrowser for help on using the repository browser.