[Zope3-Users] Custom Image Widget
Tom Dossis
td at yoma.com.au
Mon Dec 11 18:53:40 EST 2006
Adam Summers wrote:
> Hi,
>
> I have the following widgets.
>
>
> class MyImageDisplayWidget(DisplayWidget):
>
> class_ = Image
>
> def __call__(self):
> mycontent = u"oops! no img"
> if self._renderedValueSet():
> mycontent = "<img src=\"data:image/gif;base64, " +
> b64encode(self._data.data) + " \" />"
> return mycontent
>
> MyImageListDisplayWidget = CustomWidgetFactory(SequenceDisplayWidget,
> subwidget = MyImageDisplayWidget)
>
> class MyImageWidget(FileWidget):
>
> class_ = Image
>
> def _toFieldValue(self, input):
> value = super(MyImageWidget, self)._toFieldValue(input)
> return self.class_(value)
>
> MyImageListWidget = CustomWidgetFactory(ListSequenceWidget, subwidget =
> MyImageWidget)
>
> I want to build a better input widget (MyImageWidget), so that we can do
> the following:
> * If the field has no data, display a file input.
> * If the field has data, display the image.
>
> I know that there are design shortcomings in this, but I need a simple
> example (and I only use the files in lists anyway, so I can delete images).
>
> Any pointers on how to go about this would be much appreciated; as always
Hi Adam,
I'm not exactly sure of your use case, but I've included a widget
implementation (see below) which you may find useful. I've used this
widget for an attribute which is an IImage, e.g.
class IContent(zope.interface.Interface):
image=zope.schema.Object(schema=zope.app.file.interfaces.IImage)
class Content(persistent.Persistent):
# This property makes the image object locatable (see below)
image=LocatableProperty(IContent['image'])
ImageAttributeTraverser=\
z3c.traverser.traverser.SingleAttributeTraverserPlugin('image')
########## property.py
from zope import location
from zope.schema.fieldproperty import FieldProperty
def LocatableProperty(field_or_descriptor):
"""A property which ensures a field instance is locatable.
The argument can be a field or a descriptor for that field. The
zope.fieldproperty.FieldProperty descriptor is used internally
when a field object argument is passed.
A locatable property can be used for traversable attribute objects to
locate them in the referencing object.
Let's create a simple content object with an attribute which is
an image:
>>> from zope import schema
>>> from zope.app.file.interfaces import IImage
>>> image_field=schema.Object(__name__='image', schema=IImage)
>>> class Content(object):
... image=LocatableProperty(image_field)
>>> ob = Content()
>>> ob.image is None
True
Assign an image object which doesn't have location to the attribute:
>>> from zope.app.file import Image
>>> image = Image(data='1234')
>>> image.__parent__
Traceback (most recent call last):
...
AttributeError: 'Image' object has no attribute '__parent__'
>>> ob.image = image
When we now access the attribute object, it we find that is has
been wrapped inside a location proxy object:
>>> ob.image.__parent__ is ob
True
>>> ob.image.__name__
'image'
>>> ob.image.data
'1234'
"""
try:
field_or_descriptor.__get__
field_or_descriptor.__set__
return Locatable(field_or_descriptor)
except AttributeError:
return Locatable(FieldProperty(field_or_descriptor))
class Locatable(object):
"""Wrap a FieldProperty descriptor to make it's field locatable.
"""
def __init__(self, descriptor):
self.descriptor = descriptor
self.name = self.descriptor._FieldProperty__name
def __get__(self, inst, cls):
ob = self.descriptor.__get__(inst, cls)
if ob is not None:
if location.interfaces.ILocation(ob, None) is None:
ob = location.LocationProxy(ob, inst, self.name)
return ob
def __set__(self, inst, ob):
self.descriptor.__set__(inst, ob)
########## widget.py
from zope.event import notify
from zope.lifecycleevent import ObjectCreatedEvent
from zope.i18n import translate
from zope.dublincore.interfaces import IZopeDublinCore
from zope.size.interfaces import ISized
from zope.component import getMultiAdapter
from zope.traversing.browser import absoluteURL
from zope.app.file import Image
from zope.app.file.browser.image import ImageData
from zope.app.form.browser import DisplayWidget
from zope.app.form.browser import FileWidget
class ImageDisplayWidget(DisplayWidget):
def __call__(self):
field = self.context
image = field.get(field.context)
if image is None:
return u"(No image object)"
alt = IZopeDublinCore(image).title or ''
title = IZopeDublinCore(image).description or ''
v = ImageData()
v.context, v.request = image, self.request
return v.tag(alt=alt, title=title)
class ImageInputWidget(FileWidget):
def _toFieldValue(self, input):
data = super(ImageWidget, self)._toFieldValue(input)
if data is not None:
img = Image(data)
notify(ObjectCreatedEvent(img))
return img
def __call__(self):
input_widget = super(ImageWidget, self).__call__()
try:
image = ImageDisplayWidget(self.context, self.request)()
info = self.info()
return u'<br />'.join([image, info, input_widget])
except AttributeError:
# This happens because the context is IAdding
return input_widget
def info(self):
field = self.context
image = field.get(field.context)
if image is not None:
v = getMultiAdapter((image,self.request),
name='EditMetaData.html')
url = absoluteURL(v, self.request)
size = translate(ISized(image).sizeForDisplay())
title = IZopeDublinCore(image).title or ''
description = IZopeDublinCore(image).description or ''
return imageInfoText(title, description, size, url)
return ''
def imageInfoText(title, desc, size, url):
return u'<br />'.join([
'%s: %s' % (_("Size"), size),
'%s: %s <a href="%s">[%s]</a>' % (u"Title", title, url, u"Edit"),
'%s: %s <a href="%s">[%s]</a>' % (u"Description", desc, url, u"Edit"),
])
More information about the Zope3-users
mailing list