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"), ]) _______________________________________________ Zope3-users mailing list Zope3-users@zope.org http://mail.zope.org/mailman/listinfo/zope3-users