Skip to content

Commit

Permalink
- Changes: around objectwidget
Browse files Browse the repository at this point in the history
  - zcml objectWidgetTemplate to be able to register widget templates for specific field schemas
  - subwidgets prefix will come from the main-widget
  - subform discriminator on field.schema did not work
          
- Fixes: MultiWidget:
  - setting (sub)widgets early
  - setting subwidgets.form
  • Loading branch information
Adam Groszer committed Nov 25, 2008
1 parent 666909d commit c007a7f
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 13 deletions.
10 changes: 10 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ CHANGES
Version 2.0.0 (2008-??-??)
--------------------------

- Changes: around objectwidget
- zcml objectWidgetTemplate to be able to register widget templates for
specific field schemas
- subwidgets prefix will come from the main-widget
- subform discriminator on field.schema did not work

- Fixes: MultiWidget:
- setting (sub)widgets early
- setting subwidgets.form

- Feature: When no file is specified in the file upload widget, instead of
overwriting the value with a missing one, the old data is retained.

Expand Down
7 changes: 6 additions & 1 deletion src/z3c/form/meta.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
handler=".zcml.widgetTemplateDirective"
/>

<meta:directive
name="objectWidgetTemplate"
schema=".zcml.IObjectWidgetTemplateDirective"
handler=".zcml.objectWidgetTemplateDirective"
/>

</meta:directives>

</configure>

70 changes: 63 additions & 7 deletions src/z3c/form/object.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import zope.event
import zope.lifecycleevent
from zope.security.proxy import removeSecurityProxy
from zope.pagetemplate.interfaces import IPageTemplate

from z3c.pt import compat as viewpagetemplatefile
from z3c.form.converter import BaseDataConverter

from z3c.form import form, interfaces, util, widget
Expand Down Expand Up @@ -81,12 +84,14 @@ def update(self, ignoreContext=None, setErrors=True):
if interfaces.IFormAware.providedBy(self.__parent__):
self.ignoreReadonly = self.parentForm.ignoreReadonly

prefix = ''
if self.parentForm:
prefix = util.expandPrefix(self.parentForm.prefix) + \
util.expandPrefix(self.parentForm.widgets.prefix)
#prefix = ''
#if self.parentForm:
# prefix = util.expandPrefix(self.parentForm.prefix) + \
# util.expandPrefix(self.parentForm.widgets.prefix)
#
#self.prefix = prefix+self.__parent__.field.__name__

self.prefix = prefix+self.__parent__.field.__name__
self.prefix = self.__parent__.name

self.setupFields()

Expand Down Expand Up @@ -151,6 +156,8 @@ def toFieldValue(self, value):
obj = dm.get()
except KeyError:
obj = self.createObject(value)
except AttributeError:
obj = self.createObject(value)

obj = self.field.schema(obj)

Expand Down Expand Up @@ -194,7 +201,7 @@ def _getForm(self, content):

self.subform = zope.component.getMultiAdapter(
(content, self.request, self.context,
form, self, self.field, schema),
form, self, self.field, makeDummyObject(schema)),
interfaces.ISubformFactory)()

def updateWidgets(self, setErrors=True):
Expand All @@ -221,6 +228,10 @@ def value():
"""This invokes updateWidgets on any value change e.g. update/extract."""
def get(self):
return self.extract(setErrors=True)
#value = {}
#for name in zope.schema.getFieldNames(self.field.schema):
# value[name] = self.subform.widgets[name].value
#return value
def set(self, value):
self._value = value
# ensure that we apply our new values to the widgets
Expand All @@ -239,13 +250,59 @@ def extract(self, default=interfaces.NOVALUE, setErrors=True):
#while we're updating
if self._updating:
return default

raise MultipleErrors(errors)

return value

else:
return default

def render(self):
"""See z3c.form.interfaces.IWidget."""
template = self.template
if template is None:
template = zope.component.queryMultiAdapter(
(self.context, self.request, self.form, self.field, self,
makeDummyObject(self.field.schema)),
IPageTemplate, name=self.mode)
if template is None:
return super(ObjectWidget, self).render()
return template(self)

######## make dummy objects providing a given interface to support
######## discriminating on field.schema

class DummyObject(object):
zope.interface.implements(zope.interface.Interface)

def makeDummyObject(iface):
dummy = DummyObject()
if iface is not None:
zope.interface.directlyProvides(dummy, iface)
return dummy

######## special template factory that takes the field.schema into account

class ObjectWidgetTemplateFactory(object):
"""Widget template factory."""

def __init__(self, filename, contentType='text/html',
context=None, request=None, view=None,
field=None, widget=None, schema=None):
self.template = viewpagetemplatefile.ViewPageTemplateFile(
filename, content_type=contentType)
zope.component.adapter(
util.getSpecification(context),
util.getSpecification(request),
util.getSpecification(view),
util.getSpecification(field),
util.getSpecification(widget),
util.getSpecification(schema))(self)
zope.interface.implementer(IPageTemplate)(self)

def __call__(self, context, request, view, field, widget, schema):
return self.template

######## default adapters

Expand Down Expand Up @@ -274,7 +331,6 @@ def __init__(self, context, request, widgetContext, form,
self.schema = schema

def __call__(self):
#value is the extracted data from the form
obj = self.factory(self.context, self.request, self.widget)
return obj

Expand Down
19 changes: 14 additions & 5 deletions src/z3c/form/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,13 @@ class MultiWidget(Widget):
# you set showLabel to False or use another template for disable (sub)
# widget labels
showLabel = True
widgets = []
widgets = None
_value = []

def __init__(self, request):
super(MultiWidget, self).__init__(request)
self.widgets = []

@property
def counterName(self):
return '%s.count' % self.name
Expand All @@ -268,6 +272,11 @@ def getWidget(self, idx):
interfaces.IFieldWidget)
widget.name = name
widget.id = id
#set widget.form (objectwidget needs this)
if interfaces.IFormAware.providedBy(self):
widget.form = self.form
zope.interface.alsoProvides(
widget, interfaces.IFormAware)
widget.update()
return widget

Expand All @@ -281,11 +290,11 @@ def appendAddingWidget(self):
def applyValue(self, widget, value=interfaces.NOVALUE):
"""Validate and apply value to given widget.
This method get called on any multi widget vaue change and is
responsible for validate the given value and setup an error message.
This method gets called on any multi widget value change and is
responsible for validating the given value and setup an error message.
This is internal apply value and validation process is needed because
nothing outside this mutli widget does know something about our
nothing outside this multi widget does know something about our
internal sub widgets.
"""
if value is not interfaces.NOVALUE:
Expand Down Expand Up @@ -348,7 +357,7 @@ def extract(self, default=interfaces.NOVALUE, setErrors=True):
# We have to setup the widgets for extract their values, because we
# don't know how to do this for every field without the right widgets.
# Later we will setup the widgets based on this values. This is needed
# because we probably set a new value in the fornm for our multi widget
# because we probably set a new value in the form for our multi widget
# which whould generate a different set of widgets.
if self.request.get(self.counterName) is None:
# counter marker not found
Expand Down
27 changes: 27 additions & 0 deletions src/z3c/form/zcml.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from z3c.form import interfaces
from z3c.form.i18n import MessageFactory as _
from z3c.form.widget import WidgetTemplateFactory
from z3c.form.object import ObjectWidgetTemplateFactory


class IWidgetTemplateDirective(zope.interface.Interface):
Expand Down Expand Up @@ -83,6 +84,13 @@ class IWidgetTemplateDirective(zope.interface.Interface):
default='text/html',
required=False)

class IObjectWidgetTemplateDirective(IWidgetTemplateDirective):
schema = zope.configuration.fields.GlobalObject(
title=_('Schema'),
description=_('The schema of the field for which the template should be available'),
default=zope.interface.Interface,
required=False)


def widgetTemplateDirective(
_context, template, for_=zope.interface.Interface,
Expand All @@ -100,3 +108,22 @@ def widgetTemplateDirective(
# register the template
zope.component.zcml.adapter(_context, (factory,), IPageTemplate,
(for_, layer, view, field, widget), name=mode)


def objectWidgetTemplateDirective(
_context, template, for_=zope.interface.Interface,
layer=IDefaultBrowserLayer, view=None, field=None, widget=None,
schema=None,
mode=interfaces.INPUT_MODE, contentType='text/html'):

# Make sure that the template exists
template = os.path.abspath(str(_context.path(template)))
if not os.path.isfile(template):
raise ConfigurationError("No such file", template)

factory = ObjectWidgetTemplateFactory(template, contentType)
zope.interface.directlyProvides(factory, IPageTemplate)

# register the template
zope.component.zcml.adapter(_context, (factory,), IPageTemplate,
(for_, layer, view, field, widget, schema), name=mode)

0 comments on commit c007a7f

Please sign in to comment.