""" $URL: svn+ssh://svn.mems-exchange.org/repos/trunk/qp/fill/widget.qpy $ $Id: widget.qpy 29335 2007-02-09 14:21:23Z dbinger $ """ from qpy import h8, stringify from qp.fill.html import htmltag from qp.http.request import Upload from qp.pub.common import get_request def subname(prefix, name): """Create a unique name for a sub-widget or sub-component.""" return "%s__%s" % (prefix, name) def merge_attrs(base, overrides): """({string: any}, {string: any}) -> {string: any} """ items = [] if base: items.extend(base.items()) if overrides: items.extend(overrides.items()) attrs = {} for name, val in items: if name.endswith('_'): name = name[:-1] attrs[name] = val return attrs class WidgetValueError(Exception): """May be raised a widget has problems parsing its value.""" def __init__(self, msg): self.msg = msg def __str__(self): return stringify(self.msg) class Widget (object): """Abstract base class for web widgets. Instance attributes: name : string value : any error : string title : string hint : string required : bool attrs : {string: any} _parsed : bool Feel free to access these directly; to set them, use the 'set_*()' modifier methods. """ def __init__(self, name, value=None, title="", hint="", required=False, render_br=None, attrs=None, **kwattrs): # render_br is here as a keyword for the sole purpose of stopping # it from being rendered as an attr when called from code that # was really written for Quixote widgets. It will probably be # removed from a future release. assert self.__class__ is not Widget, "abstract class" self.name = name self.value = value self.error = None self.title = title self.hint = hint self.required = required self.attrs = merge_attrs(attrs, kwattrs) self._parsed = False def __repr__(self): return "<%s at %x: %s>" % (self.__class__.__name__, id(self), self.name) def __str__(self): return "%s: %s" % (self.__class__.__name__, self.name) def __iter__(self): yield self def get_name(self): return self.name def set_value(self, value): self.value = value def set_error(self, error): self.error = error def get_error(self, request=None): self.parse(request=request) return self.error def has_error(self, request=None): return bool(self.get_error(request=request)) def clear_error(self, request=None): self.parse(request=request) self.error = None def set_title(self, title): self.title = title def get_title(self): return self.title def set_hint(self, hint): self.hint = hint def get_hint(self): return self.hint def is_required(self): return self.required def is_submitted(self, request=None): if request is None: request = get_request() return self.name in request.get_fields() def parse(self, request=None): if not self._parsed: self._parsed = True if request is None: request = get_request() if self.is_submitted(request=request): try: self._parse(request) except WidgetValueError, exc: self.set_error(stringify(exc)) if (self.required and self.value is None and not self.has_error()): self.set_error('required') return self.value def _parse(self, request): # subclasses may override but this is not part of the public API value = request.get_field(self.name) if isinstance(value, basestring) and value.strip(): self.value = value else: self.value = None def render_title [html] (self, title): if title: '\n' if self.required: title += '*' '