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

Last change on this file since 6784 was 6784, checked in by uli, 13 years ago

Add a special schema field TextLineChoice?.

File size: 5.6 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$
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        # Before a default value is checked, it is validated. However, a
96        # named vocabulary is usually not complete when these fields are
97        # initialized. Therefore signal the validation method to ignore
98        # default value checks during initialization of a Choice tied to a
99        # registered vocabulary.
100        #self._init_field = (bool(self.vocabularyName) or
101        #                    IContextSourceBinder.providedBy(self.vocabulary))
102        super(TextLineChoice, self).__init__(**kw)
103        #self._init_field = False
104        return
105
106    source = property(lambda self: self.vocabulary)
107
108    def bind(self, object):
109        """See zope.schema._bootstrapinterfaces.IField."""
110        clone = super(TextLineChoice, self).bind(object)
111        # get registered vocabulary if needed:
112        if IContextSourceBinder.providedBy(self.vocabulary):
113            clone.vocabulary = self.vocabulary(object)
114            assert ISource.providedBy(clone.vocabulary)
115        elif clone.vocabulary is None and self.vocabularyName is not None:
116            vr = getVocabularyRegistry()
117            clone.vocabulary = vr.get(object, self.vocabularyName)
118            assert ISource.providedBy(clone.vocabulary)
119        return clone
120
121    def _validate(self, value):
122        """First validate against the regular TextLine rules. Then check any
123        vocabularies/sources.
124        """
125        # Do TextLine validation
126        super(TextLineChoice, self)._validate(value)
127
128        ## Pass all validations during initialization
129        #if self._init_field == 12:
130        #    return
131        # Check allowed value range (the vocabulary part)
132        vocabulary = self.vocabulary
133        if vocabulary is None and self.vocabularyName is not None:
134            vr = getVocabularyRegistry()
135            try:
136                vocabulary = vr.get(None, self.vocabularyName)
137            except VocabularyRegistryError:
138                raise ValueError("Can't validate value without vocabulary")
139        if vocabulary and value not in vocabulary:
140            raise InvalidValue(value)
141        return
Note: See TracBrowser for help on using the repository browser.