[Zope3-checkins] CVS: Zope3/src/zope/app/form/browser -
vocabularyquery.py:1.1
Stephan Richter
srichter at cosmos.phy.tufts.edu
Sat Apr 24 19:18:16 EDT 2004
Update of /cvs-repository/Zope3/src/zope/app/form/browser
In directory cvs.zope.org:/tmp/cvs-serv29400/src/zope/app/form/browser
Added Files:
vocabularyquery.py
Log Message:
The query view code moved to this module.
=== Added File Zope3/src/zope/app/form/browser/vocabularyquery.py ===
##############################################################################
#
# 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.
#
##############################################################################
"""Browser views for vocabulary widgets.
$Id: vocabularyquery.py,v 1.1 2004/04/24 23:18:16 srichter Exp $
"""
from zope.interface import implements
from zope.schema.interfaces import IIterableVocabularyQuery
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.app.publisher.browser import BrowserView
from zope.app.form.browser.itemswidgets import TranslationHook, message
from zope.app.form.browser.interfaces import IVocabularyQueryView
from zope.app.form.browser.widget import renderElement
ADD_DONE = u"adddone"
ADD_MORE = u"addmore"
MORE = u"more"
class ActionHelper(TranslationHook):
"""Helper class to allow sub-actions for a particular widget.
It is used to execute queries on a large set of vocabulary terms. Note
that a vocabulary has to support queries for this."""
__actions = None
def addAction(self, action, msgid):
"""Add an action for the widget."""
if self.__actions is None:
self.__actions = {}
assert action not in self.__actions
self.__actions[action] = msgid
def getAction(self):
"""Retrieve a the executed action from the form.
Return None, if none of the registered actions was called.
"""
assert self.__actions is not None, \
"getAction() called on %r with no actions defined" %self
for action in self.__actions.iterkeys():
name = "%s.action-%s" % (self.name, action)
if self.request.form.get(name):
return action
return None
def renderAction(self, action, disabled=False):
"""Render a particular action as a HTML submit button."""
msgid = self.__actions[action]
return ('<input type="submit" name="%s.action-%s" value=%s %s />'
% (self.name, action, quoteattr(self.translate(msgid)),
disabled and 'disabled="disabled"' or ""))
class ViewSupport(TranslationHook):
"""Helper class for vocabulary query views.
This is mixed into the query view base class.
"""
def textForValue(self, term):
"""Extract a string from the term.
The term must be a vocabulary tokenized term.
This can be overridden to support more complex term objects. The token
is returned here since it's the only thing known to be a string, or
str()able."""
return term.token
def mkselectionlist(self, type, info, name):
"""Create a list of selections."""
items = [self.mkselectionitem(type, name, *item) for item in info]
return renderElement("table",
contents="\n%s\n" % "\n".join(items))
def mkselectionitem(self, type, name, term, selected, disabled):
"""Create a single secetion item."""
flag = ''
if selected:
flag = ' checked="checked"'
if disabled:
flag += ' disabled="disabled"'
if flag:
flag = "\n " + flag
return ('<tr><td>'
'<input type="%s" value="%s" name="%s"%s />'
'</td>\n <td>%s</td></tr>'
% (type, term.token, name, flag, self.textForValue(term)))
class VocabularyQueryViewBase(ActionHelper, ViewSupport, BrowserView):
"""Vocabulary query support base class."""
implements(IVocabularyQueryView)
def __init__(self, query, field, request):
super(VocabularyQueryViewBase, self).__init__(query, request)
self.vocabulary = query.vocabulary
self.field = field
self.widget = None
def setName(self, name):
"""See interfaces.IVocabularyQueryView"""
assert not name.endswith(".")
self.name = name
def setWidget(self, widget):
assert self.widget is None
assert widget is not None
self.widget = widget
def performAction(self, value):
"""See interfaces.IVocabularyQueryView"""
return value
def renderInput(self):
"""See interfaces.IVocabularyQueryView"""
return self._renderQueryInput()
def renderResults(self, value):
"""See interfaces.IVocabularyQueryView"""
results = self._getResults()
if results is not None:
return self._renderQueryResults(results, value)
else:
return ""
def _renderQueryResults(self, results, value):
raise NotImplementedError(
"_renderQueryResults() must be implemented by a subclass")
def _renderQueryInput(self):
raise NotImplementedError(
"_renderQueryInput() must be implemented by a subclass")
def _getResults(self):
# This is responsible for running the query against the query
# object (self.context), and returning a results object. If
# there isn't a query in the form, returns None.
return None
class IterableVocabularyQueryViewBase(VocabularyQueryViewBase):
"""Query view for IIterableVocabulary objects without more
specific query views.
This should only be used (directly) for vocabularies for which
getQuery() returns None.
"""
queryResultBatchSize = 8
_msg_add_done = message(_("vocabulary-query-button-add-done"),
"Add+Done")
_msg_add_more = message(_("vocabulary-query-button-add-more"),
"Add+More")
_msg_more = message(_("vocabulary-query-button-more"),
"More")
_msg_no_results = message(_("vocabulary-query-message-no-results"),
"No Results")
_msg_results_header = message(_("vocabulary-query-header-results"),
"Search results")
def __init__(self, *args, **kw):
super(IterableVocabularyQueryViewBase, self).__init__(*args, **kw)
self.addAction(ADD_DONE, self._msg_add_done)
self.addAction(ADD_MORE, self._msg_add_more)
self.addAction(MORE, self._msg_more)
def setName(self, name):
"""See interfaces.IVocabularyQueryView"""
super(IterableVocabularyQueryViewBase, self).setName(name)
name = self.name
self.query_index_name = name + ".start"
self.query_selections_name = name + ".picks"
#
get = self.request.form.get
self.action = self.getAction()
self.query_index = None
if self.query_index_name in self.request.form:
try:
index = int(self.request.form[self.query_index_name])
except ValueError:
pass
else:
if index >= 0:
self.query_index = index
querySelections = get(self.query_selections_name, [])
if not isinstance(querySelections, list):
querySelections = [querySelections]
self.query_selections = []
for token in querySelections:
try:
term = self.vocabulary.getTermByToken(token)
except LookupError:
# XXX unsure what to pass to exception constructor
raise WidgetInputError(
"(query view for %s)" % self.context,
"(query view for %s)" % self.context,
"token %r not in vocabulary" % token)
else:
self.query_selections.append(term.value)
def _renderQueryInput(self):
# There's no query support, so we can't actually have input.
return ""
def _getResults(self):
if self.query_index is not None:
return self.vocabulary
else:
return None
def _renderQueryResults(self, results, value):
# display query results batch
it = iter(results)
qi = self.query_index
have_more = True
try:
for xxx in range(qi):
it.next()
except StopIteration:
# we should only get here with a botched request; ADD_MORE
# and MORE will normally be disabled if there are no results
# (see below)
have_more = False
items = []
querySelections = []
try:
for i in range(qi, qi + self.queryResultBatchSize):
term = it.next()
disabled = term.value in value
selected = disabled
if term.value in self.query_selections:
querySelections.append(term.value)
selected = True
items.append((term, selected, disabled))
else:
# see if there's anything else:
it.next()
except StopIteration:
if not items:
return "<div class='results'>%s</div>" % (
self.translate(self._msg_no_results))
have_more = False
self.query_selections = querySelections
return ''.join(
["<div class='results'>\n",
"<h4>%s</h4>\n" % (
self.translate(self._msg_results_header)),
self.makeSelectionList(items, self.query_selections_name),
"\n",
self.renderAction(ADD_DONE), "\n",
self.renderAction(ADD_MORE, not have_more), "\n",
self.renderAction(MORE, not have_more), "\n"
"<input type='hidden' name='%s' value='%d' />\n"
% (self.query_index_name, qi),
"</div>"])
def performAction(self, value):
"""See interfaces.IVocabularyQueryView"""
if self.action == ADD_DONE:
value = self.addSelections(value)
self.query_index = None
self.query_selections = []
elif self.action == ADD_MORE:
value = self.addSelections(value)
self.query_index += self.queryResultBatchSize
elif self.action == MORE:
self.query_index += self.queryResultBatchSize
elif self.action:
raise ValueError("unknown action in request: %r" % self.action)
return value
def addSelections(self, value):
for item in self.query_selections:
if item not in value and item in self.vocabulary:
value.append(item)
return value
class IterableVocabularyQueryView(IterableVocabularyQueryViewBase):
def makeSelectionList(self, items, name):
return self.mkselectionlist("radio", items, name)
def _renderQueryResults(self, results, value):
return super(IterableVocabularyQueryView, self)._renderQueryResults(
results, [value])
class IterableVocabularyQueryMultiView(IterableVocabularyQueryViewBase):
def makeSelectionList(self, items, name):
return self.mkselectionlist("checkbox", items, name)
More information about the Zope3-Checkins
mailing list