[Zope3-Users] stuck with zope.schema.List and subwidget

Christian Lueck christian.lueck at ruhr-uni-bochum.de
Mon Aug 29 13:15:38 EDT 2005


Stephan Richter schrieb:
> 
> The problem, I think (actually I just checked, so I know ;-), is that 
> CustomWidgetFactory was not designed to work well with advanced widgets, i.e. 
> widgets that have more constructor arguments beyond the field and the 
> request.
> 
Hm, so you think :-) I should rather use CustomSequenceWidgetFactory?
No, that doesn't work ether. (Still the same error, still don't know what to pass to 'fields'.)

But I got an other solution/suggestion: Redefine the constructor of
zope.app.form.browser.sequencewidget.SequenceWidget in new classes, say
CustomSequenceWidget and CustomListSequenceWidget. They work together
with CustomWidgetFactory (pretty) well:

from zope.app.form.browser.sequencewidget import SequenceWidget, ListSequenceWidget

class CustomSequenceWidget(SequenceWidget):
    def __init__(self, context, request, subwidget=None):
        super(SequenceWidget, self).__init__(context, request)
        self.subwidget = subwidget

class CustomListSequenceWidget(ListSequenceWidget):
    def __init__(self, context, request, subwidget=None):
        super(SequenceWidget, self).__init__(context, request)
        self.subwidget = subwidget


And then defining tuple/sequence-widgets like this:

tuplex_widget = CustomWidgetFactory(CustomSequenceWidget, subwidget=objectx_w)

listx_widget = CustomWidgetFactory(CustomListSequenceWidget, subwidget=objectx_w)


This way I got the poll-example of zope/app/form/browser/widget.txt
working, which did not work out of the box. Besides this bigger change there had
to be added some minor changes, espesially in configure.zcml

I suggest to add the two above classes to
zope/app/form/browser/sequencewidget.py

Regards
Christian


The poll-example:
----------------------------------------------------
interfaces.py
----------------------------------------------------

from zope.interface import Interface
from zope.schema import Object, Tuple, TextLine
from zope.schema.interfaces import ITextLine
from zope.i18n import MessageIDFactory

_ = MessageIDFactory("poll")

class IPollOption(Interface):

    label = TextLine(
        title=u'Label',
        min_length=1)

    description = TextLine(
        title=u'Description',
        min_length=1)

class IPoll(Interface):

    options = Tuple(
        title=u'Options',
        value_type=Object(schema=IPollOption,
                          title=u'Poll Option'))

    def getResponse(option):
        "get the response for an option"

    def choose(option):
        'user chooses an option'

----------------------------------------------------
poll.py
----------------------------------------------------

from persistent import Persistent
from interfaces import IPoll, IPollOption
from zope.interface import implements, classImplements

class PollOption(Persistent, object):
    implements(IPollOption)

class Poll(Persistent, object):
    implements(IPoll)

    def getResponse(self, option):
        return self._responses[option]

    def choose(self, option):
        self._responses[option] += 1
        self._p_changed = 1

    def get_options(self):
        return self._options

    def set_options(self, options):
        self._options = options
        self._responses = {}
        for option in self._options:
            self._responses[option.label] = 0

    options = property(get_options, set_options, None, 'fiddle options')

----------------------------------------------------
browser.py
----------------------------------------------------

from zope.app.form.browser.editview import EditView
from zope.app.form.browser.add import AddView
from zope.app.form import CustomWidgetFactory
from zope.app.form.browser import SequenceWidget, ObjectWidget

from interfaces import IPoll, IPollOption
from poll import Poll, PollOption

class PollVoteView:
    __used_for__ = IPoll

    def choose(self, option):
        self.context.choose(option)
        self.request.response.redirect('.')

class CustomSequenceWidget(SequenceWidget):

    def __init__(self, context, request, subwidget=None):
        super(SequenceWidget, self).__init__(context, request)

        self.subwidget = subwidget


ow = CustomWidgetFactory(ObjectWidget, PollOption)
sw = CustomWidgetFactory(CustomSequenceWidget, subwidget=ow)

class PollEditView(EditView):
    __used_for__ = IPoll

    options_widget = sw

class PollAddView(AddView):
    __used_for__ = IPoll

    options_widget = sw

----------------------------------------------------
configure.zcml
----------------------------------------------------

<configure xmlns='http://namespaces.zope.org/zope'
    xmlns:browser='http://namespaces.zope.org/browser'>


<content class=".poll.Poll">

  <!-- <factory id="zope.app.demo.poll" /> This path seems wrong. We don't needa factory as it is
identical with the content-class. -->

  <implements
      interface="zope.app.annotation.interfaces.IAttributeAnnotatable"
      />

  <require
      permission="zope.View"
      interface=".interfaces.IPoll"
      />

  <require
      permission="zope.ManageContent"
      set_schema=".interfaces.IPoll"
      />
</content>


<content class=".poll.PollOption">

  <require
      permission="zope.View"
      interface=".interfaces.IPollOption"
      />

</content>


<browser:page for=".interfaces.IPoll"
    name="index.html"
    template="results.zpt"
    permission="zope.View"
    menu="zmi_views" title="View"
    />

<browser:pages
    for=".interfaces.IPoll"
    class=".browser.PollVoteView"
    permission="zope.ManageContent">

  <browser:page
      name="vote.html"
      template="vote.zpt"
      menu="zmi_views" title="Vote"
      />

  <browser:page
      name="choose"
      attribute="choose" />

</browser:pages>

<browser:addform
    schema=".interfaces.IPoll"
    label="Add a Poll"
    content_factory=".poll.Poll"
    name="AddPoll.html"
    class=".browser.PollAddView"
    permission="zope.ManageContent"
    />
<!--
<browser:addMenuItem
    title="Poll Demo"
    description="Poll Demo"
    content_factory=".poll.Poll"
    view="AddPoll.html"
    permission="zope.ManageContent"
    />
-->

<browser:addMenuItem
    class=".poll.Poll"
    title="Poll Demo"
    description="Poll Demo"
    view="AddPoll.html"
    permission="zope.ManageContent"
    />

<browser:editform
    schema=".interfaces.IPoll"
    class=".browser.PollEditView"
    label="Change a Poll"
    name="edit.html"
    menu="zmi_views" title="Edit"
    permission="zope.ManageContent"
    />

</configure>

----------------------------------------------------
vote.zpt
----------------------------------------------------

<html metal:use-macro="context/@@standard_macros/page">
<title metal:fill-slot="title">Poll voting</title>
<div metal:fill-slot="body">
<form action="choose">
<table border="1">
<caption>Poll voting</caption>
<tbody>
    <tr tal:repeat="option context/options">
    <td><input type="radio" name="option"
                tal:attributes="value option/label"></td>
    <td tal:content="option/label">Option</td>
    <td tal:content="option/description">Option</td>
    </tr>
</tbody>
</table>
<input type="submit">
</form>
</div>
</html>

----------------------------------------------------
results.zpt
----------------------------------------------------

<html metal:use-macro="context/@@standard_macros/page">
<title metal:fill-slot="title">Poll results</title>
<div metal:fill-slot="body">
<table border="1">
<caption>Poll results</caption>
<thead>
    <tr><th>Option</th><th>Results</th><th>Description</th></tr>
</thead>
<tbody>
    <tr tal:repeat="option context/options">
    <td tal:content="option/label">Option</td>
    <td tal:content="python:context.getResponse(option.label)">Result</td>
    <td tal:content="option/description">Option</td>
    </tr>
</tbody>
</table>
</div>
</html>



More information about the Zope3-users mailing list